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.

2340 lines
66 KiB

  1. /*++
  2. File Description:
  3. This file contains utility functions used by the
  4. SID modifier tool.
  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. //
  23. // Private header files
  24. //
  25. #include "setupcl.h"
  26. SECURITY_INFORMATION ALL_SECURITY_INFORMATION = DACL_SECURITY_INFORMATION |
  27. SACL_SECURITY_INFORMATION |
  28. GROUP_SECURITY_INFORMATION |
  29. OWNER_SECURITY_INFORMATION;
  30. //
  31. // ISSUE-2002/02/26-brucegr,jcohen - Dead Code! Nobody calls DeleteKey!
  32. //
  33. NTSTATUS
  34. DeleteKey(
  35. PWSTR Key
  36. );
  37. NTSTATUS
  38. DeleteKeyRecursive(
  39. HANDLE hKeyRoot,
  40. PWSTR Key
  41. );
  42. NTSTATUS
  43. FileDelete(
  44. IN WCHAR *FileName
  45. );
  46. NTSTATUS
  47. FileCopy(
  48. IN WCHAR *TargetName,
  49. IN WCHAR *SourceName
  50. );
  51. NTSTATUS
  52. SetKey(
  53. IN WCHAR *KeyName,
  54. IN WCHAR *SubKeyName,
  55. IN CHAR *Data,
  56. IN ULONG DataLength,
  57. IN ULONG DATA_TYPE
  58. );
  59. NTSTATUS
  60. ReadSetWriteKey(
  61. IN WCHAR *ParentKeyName, OPTIONAL
  62. IN HANDLE ParentKeyHandle, OPTIONAL
  63. IN WCHAR *SubKeyName,
  64. IN CHAR *OldData,
  65. IN CHAR *NewData,
  66. IN ULONG DataLength,
  67. IN ULONG DATA_TYPE
  68. );
  69. NTSTATUS
  70. LoadUnloadKey(
  71. IN PWSTR KeyName,
  72. IN PWSTR FileName
  73. );
  74. NTSTATUS
  75. BackupRepairHives(
  76. VOID
  77. );
  78. NTSTATUS
  79. CleanupRepairHives(
  80. NTSTATUS RepairHivesSuccess
  81. );
  82. NTSTATUS
  83. TestSetSecurityObject(
  84. HANDLE hKey
  85. );
  86. NTSTATUS
  87. SetKeySecurityRecursive(
  88. HANDLE hKey
  89. );
  90. NTSTATUS
  91. CopyKeyRecursive(
  92. HANDLE hKeyDst,
  93. HANDLE hKeySrc
  94. );
  95. NTSTATUS
  96. CopyRegKey(
  97. IN WCHAR *TargetName,
  98. IN WCHAR *SourceName,
  99. IN HANDLE ParentKeyHandle OPTIONAL
  100. );
  101. //
  102. // ISSUE-2002/02/26-brucegr,jcohen - Dead Code! Nobody calls MoveRegKey!
  103. //
  104. NTSTATUS
  105. MoveRegKey(
  106. IN WCHAR *TargetName,
  107. IN WCHAR *SourceName
  108. );
  109. NTSTATUS
  110. FindAndReplaceBlock(
  111. IN PCHAR Block,
  112. IN ULONG BlockLength,
  113. IN PCHAR OldValue,
  114. IN PCHAR NewValue,
  115. IN ULONG ValueLength
  116. );
  117. NTSTATUS
  118. SiftKeyRecursive(
  119. HANDLE hKey,
  120. int indent
  121. );
  122. NTSTATUS
  123. SiftKey(
  124. PWSTR KeyName
  125. );
  126. //
  127. // ISSUE-2002/02/26-brucegr,jcohen - Dead Code! Nobody calls DeleteKey!
  128. //
  129. NTSTATUS
  130. DeleteKey(
  131. PWSTR KeyName
  132. )
  133. /*++
  134. ===============================================================================
  135. Routine Description:
  136. Does some overhead work, then calls out to DeleteKeyRecursive in order
  137. to ensure that if this key has any children, they get whacked too.
  138. Arguments:
  139. Key: Key to delete.
  140. Return Value:
  141. Status is returned.
  142. ===============================================================================
  143. --*/
  144. {
  145. NTSTATUS Status;
  146. UNICODE_STRING UnicodeString;
  147. OBJECT_ATTRIBUTES ObjectAttributes;
  148. WCHAR TerminateKey[MAX_PATH],
  149. ParentName[MAX_PATH];
  150. HANDLE hKey;
  151. LONG i;
  152. //
  153. // Get the name of the parent key. Do this by replacing the last
  154. // back-whack with a NULL.
  155. //
  156. i = wcslen( KeyName );
  157. while( (KeyName[i] != '\\') &&
  158. ( i >= 0 ) ) {
  159. i--;
  160. }
  161. if( i >= 0 ) {
  162. KeyName[i] = 0;
  163. wcscpy( ParentName, KeyName );
  164. KeyName[i] = '\\';
  165. } else {
  166. return( -1 );
  167. }
  168. //
  169. // Get the name of the key we're going to terminate...
  170. //
  171. wcscpy( TerminateKey, KeyName + i + 1 );
  172. //
  173. // Open the parent
  174. //
  175. INIT_OBJA( &ObjectAttributes, &UnicodeString, ParentName );
  176. ObjectAttributes.RootDirectory = NULL;
  177. Status = NtOpenKey( &hKey,
  178. KEY_ALL_ACCESS,
  179. &ObjectAttributes );
  180. TEST_STATUS_RETURN( "SETUPCL: DeleteKey - Failed to open Parent key!" );
  181. Status = DeleteKeyRecursive( hKey, TerminateKey );
  182. TEST_STATUS( "SETUPCL: DeleteKey - Call to DeleteKeyRecursive Failed!" );
  183. NtClose( hKey );
  184. return( Status );
  185. }
  186. NTSTATUS
  187. DeleteKeyRecursive(
  188. HANDLE hKeyRoot,
  189. PWSTR Key
  190. )
  191. /*++
  192. ===============================================================================
  193. Routine Description:
  194. Routine to recursively delete all subkeys under the given
  195. key, including the key given.
  196. Arguments:
  197. hKeyRoot: Handle to root relative to which the key to be deleted is
  198. specified.
  199. Key: Root relative path of the key which is to be recursively
  200. deleted.
  201. Return Value:
  202. Status is returned.
  203. ===============================================================================
  204. --*/
  205. {
  206. WCHAR ValueBuffer[BASIC_INFO_BUFFER_SIZE];
  207. ULONG ResultLength;
  208. PKEY_BASIC_INFORMATION KeyInfo;
  209. NTSTATUS Status;
  210. UNICODE_STRING UnicodeString;
  211. OBJECT_ATTRIBUTES Obja;
  212. PWSTR SubkeyName;
  213. HANDLE hKey;
  214. //
  215. // Initialize
  216. //
  217. KeyInfo = (PKEY_BASIC_INFORMATION)ValueBuffer;
  218. //
  219. // Open the key
  220. //
  221. INIT_OBJA(&Obja,&UnicodeString,Key);
  222. Obja.RootDirectory = hKeyRoot;
  223. Status = NtOpenKey( &hKey,
  224. KEY_ALL_ACCESS,
  225. &Obja);
  226. TEST_STATUS_RETURN( "SETUPCL: DeleteKeyRecursive - Failed to open key!" );
  227. //
  228. // Enumerate all subkeys of the current key. if any exist they should
  229. // be deleted first. since deleting the subkey affects the subkey
  230. // index, we always enumerate on subkeyindex 0
  231. //
  232. while(1) {
  233. Status = NtEnumerateKey( hKey,
  234. 0,
  235. KeyBasicInformation,
  236. ValueBuffer,
  237. sizeof(ValueBuffer),
  238. &ResultLength );
  239. if(!NT_SUCCESS(Status)) {
  240. break;
  241. }
  242. //
  243. // Zero-terminate the subkey name just in case.
  244. //
  245. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  246. //
  247. // Recursively call this guy with a child.
  248. //
  249. Status = DeleteKeyRecursive( hKey, KeyInfo->Name );
  250. if(!NT_SUCCESS(Status)) {
  251. break;
  252. }
  253. }
  254. //
  255. // Check the status, if the status is anything other than
  256. // STATUS_NO_MORE_ENTRIES we failed in deleting some subkey,
  257. // so we cannot delete this key too
  258. //
  259. if( Status == STATUS_NO_MORE_ENTRIES) {
  260. Status = STATUS_SUCCESS;
  261. }
  262. TEST_STATUS( "SETUPCL: DeleteKeyRecursive - Failed to delete all keys!" );
  263. Status = NtDeleteKey( hKey );
  264. TEST_STATUS( "SETUPCL: DeleteKeyRecursive - Failed to delete key!" );
  265. Status = NtClose( hKey );
  266. TEST_STATUS( "SETUPCL: DeleteKeyRecursive - Failed to close key!" );
  267. return( Status );
  268. }
  269. NTSTATUS
  270. FileDelete(
  271. IN WCHAR *FileName
  272. )
  273. /*++
  274. ===============================================================================
  275. Routine Description:
  276. This function will attempt a delete on the given file name.
  277. Arguments:
  278. FileName - The name of the file we're going to be deleting.
  279. Return Value:
  280. NTSTATUS.
  281. ===============================================================================
  282. --*/
  283. {
  284. NTSTATUS Status = STATUS_SUCCESS;
  285. UNICODE_STRING UnicodeString;
  286. OBJECT_ATTRIBUTES ObjectAttributes;
  287. HANDLE hFile;
  288. IO_STATUS_BLOCK IoStatusBlock;
  289. WCHAR buffer[MAX_PATH];
  290. INIT_OBJA( &ObjectAttributes,
  291. &UnicodeString,
  292. FileName );
  293. Status = NtCreateFile( &hFile,
  294. FILE_GENERIC_READ | DELETE,
  295. &ObjectAttributes,
  296. &IoStatusBlock,
  297. NULL,
  298. FILE_ATTRIBUTE_NORMAL,
  299. 0,
  300. FILE_OPEN,
  301. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE,
  302. NULL,
  303. 0 );
  304. //
  305. // ISSUE-2002/02/26-brucegr,jcohen - Check Status before trying to close handle!
  306. //
  307. NtClose( hFile );
  308. TEST_STATUS( "SETUPCL: MyDelFile - Failed a delete." );
  309. return( Status );
  310. }
  311. NTSTATUS
  312. FileCopy(
  313. IN WCHAR *TargetName,
  314. IN WCHAR *SourceName
  315. )
  316. /*++
  317. ===============================================================================
  318. Routine Description:
  319. This function will attempt a copy of the given file.
  320. Arguments:
  321. TargetName - The name of the file we'll be writing.
  322. SourceName - The name of the file we'll be reading.
  323. Return Value:
  324. NTSTATUS.
  325. ===============================================================================
  326. --*/
  327. {
  328. NTSTATUS Status = STATUS_SUCCESS;
  329. UNICODE_STRING UnicodeString;
  330. OBJECT_ATTRIBUTES ObjectAttributes;
  331. HANDLE SourceHandle,
  332. TargetHandle,
  333. SectionHandle;
  334. IO_STATUS_BLOCK IoStatusBlock;
  335. ULONG FileSize,
  336. remainingLength,
  337. writeLength;
  338. SIZE_T ViewSize;
  339. LARGE_INTEGER SectionOffset,
  340. FileOffset;
  341. PVOID ImageBase;
  342. PUCHAR base;
  343. FILE_STANDARD_INFORMATION StandardInfo;
  344. //
  345. // Open the Source file.
  346. //
  347. INIT_OBJA( &ObjectAttributes,
  348. &UnicodeString,
  349. SourceName );
  350. Status = NtCreateFile( &SourceHandle,
  351. FILE_GENERIC_READ,
  352. &ObjectAttributes,
  353. &IoStatusBlock,
  354. NULL,
  355. FILE_ATTRIBUTE_NORMAL,
  356. FILE_SHARE_READ,
  357. FILE_OPEN,
  358. 0,
  359. NULL,
  360. 0 );
  361. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed to open source." );
  362. //
  363. // Get the Source file size.
  364. //
  365. Status = NtQueryInformationFile( SourceHandle,
  366. &IoStatusBlock,
  367. &StandardInfo,
  368. sizeof(StandardInfo),
  369. FileStandardInformation );
  370. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed to get Source StandardInfo." );
  371. FileSize = StandardInfo.EndOfFile.LowPart;
  372. //
  373. // Map the Source file.
  374. //
  375. ViewSize = 0;
  376. SectionOffset.QuadPart = 0;
  377. Status = NtCreateSection( &SectionHandle,
  378. STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
  379. NULL,
  380. NULL, // entire file
  381. PAGE_READONLY,
  382. SEC_COMMIT,
  383. SourceHandle );
  384. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed CreateSection on Source." );
  385. ImageBase = NULL;
  386. Status = NtMapViewOfSection( SectionHandle,
  387. NtCurrentProcess(),
  388. &ImageBase,
  389. 0,
  390. 0,
  391. &SectionOffset,
  392. &ViewSize,
  393. ViewShare,
  394. 0,
  395. PAGE_READONLY );
  396. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed MapViewOfSection on Source." );
  397. //
  398. // Open the Target file.
  399. //
  400. INIT_OBJA( &ObjectAttributes,
  401. &UnicodeString,
  402. TargetName );
  403. Status = NtCreateFile( &TargetHandle,
  404. FILE_GENERIC_WRITE,
  405. &ObjectAttributes,
  406. &IoStatusBlock,
  407. NULL,
  408. FILE_ATTRIBUTE_NORMAL,
  409. 0,
  410. FILE_OVERWRITE_IF,
  411. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  412. NULL,
  413. 0 );
  414. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed to open target." );
  415. //
  416. // Write him. We guard him with a try/except because if there is an
  417. // i/o error, memory management will raise an in-page exception.
  418. //
  419. FileOffset.QuadPart = 0;
  420. base = ImageBase;
  421. remainingLength = FileSize;
  422. try {
  423. while( remainingLength != 0 ) {
  424. writeLength = 60 * 1024;
  425. if( writeLength > remainingLength ) {
  426. writeLength = remainingLength;
  427. }
  428. Status = NtWriteFile( TargetHandle,
  429. NULL,
  430. NULL,
  431. NULL,
  432. &IoStatusBlock,
  433. base,
  434. writeLength,
  435. &FileOffset,
  436. NULL );
  437. base += writeLength;
  438. FileOffset.LowPart += writeLength;
  439. remainingLength -= writeLength;
  440. if( !NT_SUCCESS( Status ) ) {
  441. break;
  442. }
  443. }
  444. } except( EXCEPTION_EXECUTE_HANDLER ) {
  445. Status = STATUS_IN_PAGE_ERROR;
  446. }
  447. NtClose( TargetHandle );
  448. TEST_STATUS_RETURN( "SETUPCL: FileCopy - Failed to write target." );
  449. //
  450. // Unmap the source file.
  451. //
  452. Status = NtUnmapViewOfSection( NtCurrentProcess(), ImageBase );
  453. TEST_STATUS( "SETUPCL: FileCopy - Failed to UnMapSection on source." );
  454. Status = NtClose( SectionHandle );
  455. TEST_STATUS( "SETUPCL: FileCopy - Failed to close sectionhandle on source." );
  456. NtClose( SourceHandle );
  457. return( Status );
  458. }
  459. NTSTATUS
  460. SetKey(
  461. IN WCHAR *KeyName,
  462. IN WCHAR *SubKeyName,
  463. IN CHAR *Data,
  464. IN ULONG DataLength,
  465. IN ULONG DATA_TYPE
  466. )
  467. /*++
  468. ===============================================================================
  469. Routine Description:
  470. This function will set the specified key to the specified value.
  471. Arguments:
  472. KeyName - The name of the key we're going to be setting.
  473. SubKeyName - The name of the Value key we're setting
  474. Data - The value we'll be setting him to.
  475. DataLength - How much data are we writing?
  476. DATA_TYPE - Type of the registry entry
  477. Return Value:
  478. NTSTATUS.
  479. ===============================================================================
  480. --*/
  481. {
  482. NTSTATUS Status;
  483. UNICODE_STRING UnicodeString,
  484. ValueName;
  485. OBJECT_ATTRIBUTES ObjectAttributes;
  486. HANDLE hKey;
  487. //
  488. // Open the parent key.
  489. //
  490. INIT_OBJA( &ObjectAttributes,
  491. &UnicodeString,
  492. KeyName );
  493. Status = NtOpenKey( &hKey,
  494. KEY_ALL_ACCESS,
  495. &ObjectAttributes );
  496. if( !NT_SUCCESS( Status ) ) {
  497. DbgPrint( "SETUPCL: SetKey - Failed to open %ws (%lx)\n", KeyName, Status );
  498. return( Status );
  499. }
  500. //
  501. // Now write the target key.
  502. //
  503. RtlInitUnicodeString(&ValueName, SubKeyName );
  504. Status = NtSetValueKey( hKey,
  505. &ValueName, // SubKeyName
  506. 0, // TitleIndex
  507. DATA_TYPE, // Type
  508. Data, // value
  509. DataLength );
  510. if( !NT_SUCCESS( Status ) ) {
  511. DbgPrint( "SETUPCL: SetKey - Failed to Set %ws\\%ws (%lx)\n", KeyName, SubKeyName, Status );
  512. //
  513. // ISSUE-2002/02/26-brucegr,jcohen - If NtSetValueKey fails, hKey is leaked!
  514. //
  515. return( Status );
  516. }
  517. NtFlushKey( hKey );
  518. NtClose( hKey );
  519. return( Status );
  520. }
  521. NTSTATUS
  522. ReadSetWriteKey(
  523. IN WCHAR *ParentKeyName, OPTIONAL
  524. IN HANDLE ParentKeyHandle, OPTIONAL
  525. IN WCHAR *SubKeyName,
  526. IN CHAR *OldData,
  527. IN CHAR *NewData,
  528. IN ULONG DataLength,
  529. IN ULONG DATA_TYPE
  530. )
  531. /*++
  532. ===============================================================================
  533. Routine Description:
  534. This function will read a value from a key, surgically replace some bits
  535. in it, then write it back out.
  536. Arguments:
  537. ParentKeyName - Parent name of the key we're going to be setting.
  538. ParentKeyHandle - Parent handle of the key we're going to be setting.
  539. SubKeyName - The name of the Value key we're setting
  540. Data - The value we'll be setting him to.
  541. DataLength - How much data are we writing?
  542. DATA_TYPE - Type of the registry entry
  543. Return Value:
  544. NTSTATUS.
  545. ===============================================================================
  546. --*/
  547. {
  548. NTSTATUS Status;
  549. UNICODE_STRING UnicodeString,
  550. ValueName;
  551. OBJECT_ATTRIBUTES ObjectAttributes;
  552. HANDLE hKey;
  553. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
  554. ULONG KeyValueLength, LengthNeeded;
  555. if( ParentKeyHandle == NULL ) {
  556. //
  557. // Open the parent key.
  558. //
  559. INIT_OBJA( &ObjectAttributes,
  560. &UnicodeString,
  561. ParentKeyName );
  562. Status = NtOpenKey( &hKey,
  563. KEY_ALL_ACCESS,
  564. &ObjectAttributes );
  565. if( !NT_SUCCESS( Status ) ) {
  566. DbgPrint( "SETUPCL: ReadSetWriteKey - Failed to open %ws (%lx)\n", ParentKeyName, Status );
  567. return( Status );
  568. }
  569. } else {
  570. hKey = ParentKeyHandle;
  571. }
  572. //
  573. // Get his data.
  574. //
  575. RtlInitUnicodeString( &UnicodeString, SubKeyName );
  576. //
  577. // How big is his buffer?
  578. //
  579. Status = NtQueryValueKey( hKey,
  580. &UnicodeString,
  581. KeyValuePartialInformation,
  582. NULL,
  583. 0,
  584. &LengthNeeded );
  585. //
  586. // ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
  587. //
  588. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  589. DbgPrint( "SETUPCL: ReadSetWriteKey - Unable to query subkey %ws size. Error (%lx)\n", SubKeyName, Status );
  590. //
  591. // ISSUE-2002/02/26-brucegr,jcohen - Leaks key if ParentKeyHandle == NULL
  592. //
  593. return( Status );
  594. } else {
  595. Status = STATUS_SUCCESS;
  596. }
  597. //
  598. // Allocate a block.
  599. //
  600. LengthNeeded += 0x10;
  601. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  602. 0,
  603. LengthNeeded );
  604. if( KeyValueInfo == NULL ) {
  605. DbgPrint( "SETUPCL: ReadSetWriteKey - Unable to allocate buffer\n" );
  606. //
  607. // ISSUE-2002/02/26-brucegr,jcohen - Leaks key if ParentKeyHandle == NULL
  608. //
  609. return( Status );
  610. }
  611. //
  612. // Get the data.
  613. //
  614. Status = NtQueryValueKey( hKey,
  615. &UnicodeString,
  616. KeyValuePartialInformation,
  617. (PVOID)KeyValueInfo,
  618. LengthNeeded,
  619. &KeyValueLength );
  620. if( !NT_SUCCESS( Status ) ) {
  621. DbgPrint( "SETUPCL: ReadSetWriteKey - Failed to query subkey %ws (%lx)\n", SubKeyName, Status );
  622. //
  623. // ISSUE-2002/02/26-brucegr,jcohen - Leaks key if ParentKeyHandle == NULL
  624. // ISSUE-2002/02/26-brucegr,jcohen - Leaks KeyValueInfo
  625. //
  626. return( Status );
  627. }
  628. //
  629. // We got it. Now we need to implant our new Sid into KeyValueInfo and
  630. // write him back out. This is really gross...
  631. //
  632. // We're not going to rely on this structure being constant. We'll
  633. // brute force the replacement via a call to FindAndReplaceBlock. This
  634. // should insulate us from changes to this structure.
  635. //
  636. if( DATA_TYPE == REG_SZ ) {
  637. //
  638. // ISSUE - 2002/03/01-brucegr,acosma: We should handle REG_MULTI_SZ like a string instead of binary data
  639. //
  640. //
  641. // The user sent us a set of strings. Use StringSwitchString
  642. // and ignore the DataLength he sent us.
  643. //
  644. Status = StringSwitchString( (PWCHAR)&KeyValueInfo->Data,
  645. (DWORD) LengthNeeded / sizeof(WCHAR),
  646. (PWCHAR)(OldData),
  647. (PWCHAR)(NewData) );
  648. //
  649. // Need to update KeyValueInfo->DataLength because SID string may have changed size!
  650. //
  651. if ( NT_SUCCESS( Status ) )
  652. {
  653. //
  654. // StringSwitchString may have changed the length. Make sure we're in sync.
  655. //
  656. KeyValueInfo->DataLength = (wcslen((PWCHAR) KeyValueInfo->Data) + 1) * sizeof(WCHAR);
  657. }
  658. } else {
  659. //
  660. // Treat it as a some non-string.
  661. //
  662. Status = FindAndReplaceBlock( (PUCHAR)&KeyValueInfo->Data,
  663. KeyValueInfo->DataLength,
  664. (PUCHAR)(OldData),
  665. (PUCHAR)(NewData),
  666. DataLength );
  667. }
  668. if( NT_SUCCESS( Status ) ) {
  669. //
  670. // Now write the structure back into the registry key.
  671. //
  672. Status = NtSetValueKey( hKey,
  673. &UnicodeString,
  674. 0,
  675. DATA_TYPE,
  676. (PVOID)KeyValueInfo->Data,
  677. KeyValueInfo->DataLength );
  678. if( !NT_SUCCESS( Status ) ) {
  679. DbgPrint( "SETUPCL: ReadSetWriteKey - Failed to set subkey %ws (%lx)\n", SubKeyName, Status );
  680. } else {
  681. #if 0
  682. DbgPrint( "SETUPCL: ReadSetWriteKey - We updated key %ws\\%ws.\n", ParentKeyName, SubKeyName );
  683. #endif
  684. }
  685. NtFlushKey( hKey );
  686. }
  687. //
  688. // Clean up.
  689. //
  690. RtlFreeHeap( RtlProcessHeap(),
  691. 0,
  692. KeyValueInfo );
  693. //
  694. // Yuck. Don't close him if he came in as the ParentKeyHandle.
  695. //
  696. if( !ParentKeyHandle ) {
  697. NtClose( hKey );
  698. }
  699. return( Status );
  700. }
  701. NTSTATUS
  702. LoadUnloadHive(
  703. IN PWSTR KeyName,
  704. IN PWSTR FileName
  705. )
  706. /*++
  707. ===============================================================================
  708. Routine Description:
  709. This function will load a hive from a file.
  710. Arguments:
  711. KeyName - The name of the hive we'll be loading/saving.
  712. FileName - The name of the file we'll be loading/saving.
  713. Return Value:
  714. NTSTATUS.
  715. ===============================================================================
  716. --*/
  717. {
  718. NTSTATUS Status;
  719. UNICODE_STRING KeyNameUString,
  720. FileNameUString;
  721. OBJECT_ATTRIBUTES ObjectAttributesKey,
  722. ObjectAttributesFile;
  723. INIT_OBJA( &ObjectAttributesKey,
  724. &KeyNameUString,
  725. KeyName );
  726. ObjectAttributesKey.RootDirectory = NULL;
  727. if( FileName == NULL ) {
  728. //
  729. // Delete the key
  730. //
  731. Status = NtUnloadKey( &ObjectAttributesKey );
  732. TEST_STATUS( "SETUPCL: LoadUnloadHive - Failed to unload the key." );
  733. } else {
  734. //
  735. // Load the key from a file.
  736. //
  737. INIT_OBJA( &ObjectAttributesFile, &FileNameUString, FileName );
  738. ObjectAttributesFile.RootDirectory = NULL;
  739. Status = NtLoadKey( &ObjectAttributesKey, &ObjectAttributesFile );
  740. TEST_STATUS( "SETUPCL: LoadUnloadHive - Failed to load the key." );
  741. }
  742. return( Status );
  743. }
  744. NTSTATUS
  745. BackupRepairHives(
  746. )
  747. /*++
  748. ===============================================================================
  749. Routine Description:
  750. Make a double-secret copy of the repair hives in case we
  751. get halfway through operating on them and something goes wrong.
  752. Arguments:
  753. None.
  754. Return Value:
  755. NTSTATUS.
  756. ===============================================================================
  757. --*/
  758. {
  759. NTSTATUS Status = STATUS_SUCCESS;
  760. //
  761. // We'd like to make a backup copy of the repair hives before we mess with
  762. // them. This way, if something goes wrong, we can restore the originals
  763. // and leave the repair hives with the old SID.
  764. //
  765. DbgPrint( "\nAbout to copy repair SAM hive.\n" );
  766. Status = FileCopy( TEXT( BACKUP_REPAIR_SAM_HIVE ),
  767. TEXT( REPAIR_SAM_HIVE ) );
  768. TEST_STATUS_RETURN( "SETUPCL: BackupRepairHives - Failed to save backup repair SAM hive." );
  769. DbgPrint( "About to copy repair SECURITY hive.\n" );
  770. Status = FileCopy( TEXT( BACKUP_REPAIR_SECURITY_HIVE ),
  771. TEXT( REPAIR_SECURITY_HIVE ) );
  772. TEST_STATUS_RETURN( "SETUPCL: BackupRepairHives - Failed to save backup repair SECURITY hive." );
  773. DbgPrint( "About to copy repair SOFTWARE hive.\n" );
  774. Status = FileCopy( TEXT( BACKUP_REPAIR_SOFTWARE_HIVE ),
  775. TEXT( REPAIR_SOFTWARE_HIVE ) );
  776. TEST_STATUS_RETURN( "SETUPCL: BackupRepairHives - Failed to save backup repair SOFTWARE hive." );
  777. DbgPrint( "About to copy repair SYSTEM hive.\n" );
  778. Status = FileCopy( TEXT( BACKUP_REPAIR_SYSTEM_HIVE ),
  779. TEXT( REPAIR_SYSTEM_HIVE ) );
  780. TEST_STATUS_RETURN( "SETUPCL: BackupRepairHives - Failed to save backup repair SYSTEM hive." );
  781. return( Status );
  782. }
  783. NTSTATUS
  784. CleanupRepairHives(
  785. NTSTATUS RepairHivesSuccess
  786. )
  787. /*++
  788. ===============================================================================
  789. Routine Description:
  790. Decide whether or not to restore the repair hives from the backups
  791. we made.
  792. Delete the backups we made.
  793. Arguments:
  794. None.
  795. Return Value:
  796. NTSTATUS.
  797. ===============================================================================
  798. --*/
  799. {
  800. NTSTATUS Status = STATUS_SUCCESS;
  801. //
  802. // See if we need to restore the repair hives from the backups
  803. // we made.
  804. //
  805. if( !NT_SUCCESS(RepairHivesSuccess) ) {
  806. //
  807. // Replace the repair hives with the backups. This will "undo"
  808. // any problems that happened while we were trying to update
  809. // the domain SID in the repair hives.
  810. //
  811. DbgPrint( "About to restore from backup repair hives.\n" );
  812. Status = FileCopy( TEXT( REPAIR_SAM_HIVE ),
  813. TEXT( BACKUP_REPAIR_SAM_HIVE ) );
  814. TEST_STATUS_RETURN( "SETUPCL: CleanupRepairHives - Failed to restore SAM hive from backup." );
  815. Status = FileCopy( TEXT( REPAIR_SECURITY_HIVE ),
  816. TEXT( BACKUP_REPAIR_SECURITY_HIVE ) );
  817. TEST_STATUS_RETURN( "SETUPCL: CleanupRepairHives - Failed to restore SECURITY hive from backup." );
  818. Status = FileCopy( TEXT( REPAIR_SOFTWARE_HIVE ),
  819. TEXT( BACKUP_REPAIR_SOFTWARE_HIVE ) );
  820. TEST_STATUS_RETURN( "SETUPCL: CleanupRepairHives - Failed to restore SOFTWARE hive from backup." );
  821. Status = FileCopy( TEXT( REPAIR_SYSTEM_HIVE ),
  822. TEXT( BACKUP_REPAIR_SYSTEM_HIVE ) );
  823. TEST_STATUS_RETURN( "SETUPCL: CleanupRepairHives - Failed to restore SYSTEM hive from backup." );
  824. }
  825. //
  826. // Delete the backups of the repair hives.
  827. //
  828. DbgPrint( "About to delete backup repair hives.\n" );
  829. Status = FileDelete( TEXT( BACKUP_REPAIR_SAM_HIVE ) );
  830. TEST_STATUS( "SETUPCL: CleanupRepairHives - Failed to delete backup repair SAM hive." );
  831. Status = FileDelete( TEXT( BACKUP_REPAIR_SECURITY_HIVE ) );
  832. TEST_STATUS( "SETUPCL: CleanupRepairHives - Failed to delete backup repair SECURITY hive." );
  833. Status = FileDelete( TEXT( BACKUP_REPAIR_SOFTWARE_HIVE ) );
  834. TEST_STATUS( "SETUPCL: CleanupRepairHives - Failed to delete backup repair SOFTWARE hive." );
  835. Status = FileDelete( TEXT( BACKUP_REPAIR_SYSTEM_HIVE ) );
  836. TEST_STATUS( "SETUPCL: CleanupRepairHives - Failed to delete backup repair SYSTEM hive." );
  837. return( Status );
  838. }
  839. NTSTATUS
  840. TestSetSecurityObject(
  841. HANDLE handle
  842. )
  843. /*++
  844. ===============================================================================
  845. Routine Description:
  846. This function will read security information from the object. It
  847. will then see if that security info contains any instances of the
  848. old SID. If we find any, we'll replace them with the new SID.
  849. Arguments:
  850. hKey - Handle of the object we're operating on.
  851. Return Value:
  852. NTSTATUS.
  853. ===============================================================================
  854. --*/
  855. {
  856. NTSTATUS Status = STATUS_SUCCESS;
  857. PSECURITY_DESCRIPTOR pSD;
  858. ULONG ResultLength,
  859. ShadowLength;
  860. INT i;
  861. //
  862. // Find out how big the descriptor is.
  863. //
  864. Status = NtQuerySecurityObject( handle,
  865. ALL_SECURITY_INFORMATION,
  866. NULL,
  867. 0,
  868. &ShadowLength );
  869. if (Status != STATUS_BUFFER_TOO_SMALL) {
  870. DbgPrint( "SETUPCL: TestSetSecurityObject - Failed to query object security for size (%lx)\n", Status);
  871. return( Status );
  872. }
  873. //
  874. // Allocate our buffer.
  875. //
  876. pSD = (PSECURITY_DESCRIPTOR)RtlAllocateHeap( RtlProcessHeap(),
  877. 0,
  878. ShadowLength + 0x10 );
  879. if( !pSD ) {
  880. return STATUS_NO_MEMORY;
  881. }
  882. //
  883. // Load the security info, whack it, and write it back out.
  884. //
  885. Status = NtQuerySecurityObject( handle,
  886. ALL_SECURITY_INFORMATION,
  887. pSD,
  888. ShadowLength + 0x10,
  889. &ResultLength );
  890. TEST_STATUS( "SETUPCL: TestSetSecurityObject - Failed to query security info." );
  891. Status = FindAndReplaceBlock( (PUCHAR)pSD,
  892. ShadowLength,
  893. (PUCHAR)G_OldSid + (SID_SIZE - 0xC),
  894. (PUCHAR)G_NewSid + (SID_SIZE - 0xC),
  895. 0xC );
  896. if( NT_SUCCESS( Status ) ) {
  897. //
  898. // We hit. Write out the new security info.
  899. //
  900. Status = NtSetSecurityObject( handle,
  901. ALL_SECURITY_INFORMATION,
  902. pSD );
  903. TEST_STATUS( "SETUPCL: TestSetSecurityObject - Failed to set security info." );
  904. }
  905. //
  906. // Clean up.
  907. //
  908. RtlFreeHeap( RtlProcessHeap(),
  909. 0,
  910. pSD );
  911. return( STATUS_SUCCESS );
  912. }
  913. NTSTATUS
  914. SetKeySecurityRecursive(
  915. HANDLE hKey
  916. )
  917. /*++
  918. ===============================================================================
  919. Routine Description:
  920. Set security on a registry tree.
  921. Arguments:
  922. hKey - Handle of the key we're operating on.
  923. Return Value:
  924. NTSTATUS.
  925. ===============================================================================
  926. --*/
  927. {
  928. NTSTATUS Status = STATUS_SUCCESS;
  929. PKEY_FULL_INFORMATION FullKeyInfo;
  930. PKEY_BASIC_INFORMATION BasicKeyInfo;
  931. OBJECT_ATTRIBUTES Obja;
  932. UNICODE_STRING UnicodeString;
  933. HANDLE hKeyChild;
  934. ULONG ResultLength;
  935. DWORD dwNumSubKeys;
  936. Status = TestSetSecurityObject( hKey );
  937. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Failed call out to TestSetSecurityObject()." );
  938. //
  939. // Alocate a buffer for KEY_FULL_INFORMATION
  940. //
  941. FullKeyInfo = (PKEY_FULL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  942. 0,
  943. FULL_INFO_BUFFER_SIZE );
  944. if (FullKeyInfo)
  945. {
  946. Status = NtQueryKey( hKey,
  947. KeyFullInformation,
  948. FullKeyInfo,
  949. FULL_INFO_BUFFER_SIZE,
  950. &ResultLength);
  951. //
  952. // Even if the call above failed this will be caught below.
  953. //
  954. dwNumSubKeys = FullKeyInfo->SubKeys;
  955. //
  956. // Free the memory right away after getting the number of subkeys.
  957. //
  958. RtlFreeHeap( RtlProcessHeap(),
  959. 0,
  960. FullKeyInfo );
  961. if (NT_SUCCESS(Status))
  962. {
  963. //
  964. // Alocate a buffer for KEY_BASIC_INFORMATION
  965. //
  966. BasicKeyInfo = (PKEY_BASIC_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  967. 0,
  968. BASIC_INFO_BUFFER_SIZE );
  969. if (BasicKeyInfo)
  970. {
  971. DWORD dwSubKeyCount;
  972. for ( dwSubKeyCount = 0; dwSubKeyCount < dwNumSubKeys; dwSubKeyCount++ )
  973. {
  974. Status = NtEnumerateKey( hKey,
  975. dwSubKeyCount,
  976. KeyBasicInformation,
  977. BasicKeyInfo,
  978. BASIC_INFO_BUFFER_SIZE,
  979. &ResultLength );
  980. if (NT_SUCCESS(Status))
  981. {
  982. //
  983. // Zero-terminate the subkey name just in case.
  984. //
  985. BasicKeyInfo->Name[BasicKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  986. //
  987. // Generate a handle for this child key and call ourselves again.
  988. //
  989. INIT_OBJA( &Obja, &UnicodeString, BasicKeyInfo->Name );
  990. Obja.RootDirectory = hKey;
  991. Status = NtOpenKey( &hKeyChild,
  992. KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY,
  993. &Obja );
  994. if ( NT_SUCCESS(Status) )
  995. {
  996. Status = SetKeySecurityRecursive( hKeyChild );
  997. NtClose( hKeyChild );
  998. }
  999. else
  1000. {
  1001. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Failed to open child key." );
  1002. }
  1003. }
  1004. else
  1005. {
  1006. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Failed to enumerate key." );
  1007. }
  1008. }
  1009. //
  1010. // Free the memory held for the children
  1011. //
  1012. RtlFreeHeap( RtlProcessHeap(),
  1013. 0,
  1014. BasicKeyInfo );
  1015. }
  1016. else
  1017. {
  1018. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Out of memory when allocating BasicKeyInfo." );
  1019. }
  1020. }
  1021. else
  1022. {
  1023. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Failed to query full key information." );
  1024. }
  1025. }
  1026. else
  1027. {
  1028. TEST_STATUS( "SETUPCL: SetKeySecurityRecursive - Out of memory when allocating FullKeyInfo." );
  1029. }
  1030. return( Status );
  1031. }
  1032. NTSTATUS
  1033. CopyKeyRecursive(
  1034. HANDLE hKeyDst,
  1035. HANDLE hKeySrc
  1036. )
  1037. /*++
  1038. ===============================================================================
  1039. Routine Description:
  1040. Copy a registry key (and all its subkeys) to a new key.
  1041. Arguments:
  1042. hKeyDst - Handle of the new key we're going to create.
  1043. hKeySrc - Handle of the key we're copying.
  1044. Return Value:
  1045. NTSTATUS.
  1046. ===============================================================================
  1047. --*/
  1048. {
  1049. NTSTATUS Status = STATUS_SUCCESS;
  1050. OBJECT_ATTRIBUTES ObjaSrc,
  1051. ObjaDst;
  1052. UNICODE_STRING UnicodeStringSrc,
  1053. UnicodeStringDst,
  1054. UnicodeStringValue;
  1055. HANDLE hKeySrcChild = NULL,
  1056. hKeyDstChild = NULL;
  1057. ULONG ResultLength,
  1058. BufferLength,
  1059. Index;
  1060. WCHAR ValueBuffer[FULL_INFO_BUFFER_SIZE],
  1061. TmpChar;
  1062. PSECURITY_DESCRIPTOR pSD = NULL;
  1063. PKEY_BASIC_INFORMATION KeyInfo;
  1064. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  1065. //
  1066. // Enumerate all keys in the source key and recursively create
  1067. // all the subkeys
  1068. //
  1069. KeyInfo = (PKEY_BASIC_INFORMATION) ValueBuffer;
  1070. for( Index = 0; ; Index++ )
  1071. {
  1072. Status = NtEnumerateKey( hKeySrc, Index, KeyBasicInformation, ValueBuffer, sizeof( ValueBuffer ), &ResultLength );
  1073. if ( !NT_SUCCESS(Status) )
  1074. {
  1075. if( Status == STATUS_NO_MORE_ENTRIES)
  1076. {
  1077. Status = STATUS_SUCCESS;
  1078. }
  1079. else
  1080. {
  1081. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - failed to enumerate src keys." );
  1082. }
  1083. break;
  1084. }
  1085. //
  1086. // Zero-terminate the subkey name just in case.
  1087. //
  1088. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  1089. //
  1090. // Generate key handles for these children and call ourselves again.
  1091. //
  1092. INIT_OBJA( &ObjaSrc, &UnicodeStringSrc, KeyInfo->Name );
  1093. ObjaSrc.RootDirectory = hKeySrc;
  1094. Status = NtOpenKey( &hKeySrcChild, KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY, &ObjaSrc );
  1095. if ( NT_SUCCESS(Status) )
  1096. {
  1097. Status = NtQuerySecurityObject( hKeySrcChild, ALL_SECURITY_INFORMATION, NULL, 0, &BufferLength );
  1098. if ( Status == STATUS_BUFFER_TOO_SMALL )
  1099. {
  1100. //
  1101. // Allocate our buffer.
  1102. //
  1103. if ( pSD = (PSECURITY_DESCRIPTOR)RtlAllocateHeap( RtlProcessHeap(), 0, BufferLength ) )
  1104. {
  1105. //
  1106. // Load the security info from the sources key.
  1107. //
  1108. Status = NtQuerySecurityObject( hKeySrcChild,
  1109. ALL_SECURITY_INFORMATION,
  1110. pSD,
  1111. BufferLength,
  1112. &ResultLength );
  1113. }
  1114. else
  1115. {
  1116. Status = STATUS_NO_MEMORY;
  1117. }
  1118. }
  1119. else
  1120. {
  1121. TEST_STATUS( "SETUPCL: CopyKeyRecursive - Failed to query object security for size.");
  1122. }
  1123. if ( NT_SUCCESS(Status) )
  1124. {
  1125. INIT_OBJA( &ObjaDst, &UnicodeStringDst, KeyInfo->Name );
  1126. ObjaDst.RootDirectory = hKeyDst;
  1127. ObjaDst.SecurityDescriptor = pSD;
  1128. Status = NtCreateKey( &hKeyDstChild,
  1129. KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY,
  1130. &ObjaDst,
  1131. 0,
  1132. NULL,
  1133. REG_OPTION_NON_VOLATILE,
  1134. NULL );
  1135. if ( NT_SUCCESS(Status) )
  1136. {
  1137. // Call ourselves to copy the child keys.
  1138. //
  1139. Status = CopyKeyRecursive( hKeyDstChild, hKeySrcChild );
  1140. TEST_STATUS("SETUPCL: CopyKeyRecursive - Recursive call failed.");
  1141. NtClose( hKeyDstChild );
  1142. }
  1143. else
  1144. {
  1145. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - Failed to create destination child key." );
  1146. }
  1147. }
  1148. else
  1149. {
  1150. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - Failed to get key security descriptor." );
  1151. }
  1152. // If we allocated a buffer for the security descriptor, free it now.
  1153. //
  1154. if ( pSD )
  1155. {
  1156. RtlFreeHeap( RtlProcessHeap(), 0, pSD );
  1157. pSD = NULL;
  1158. }
  1159. NtClose( hKeySrcChild );
  1160. }
  1161. else
  1162. {
  1163. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - Failed to open source child key." );
  1164. }
  1165. }
  1166. //
  1167. // We don't really care about the return value here since even if something above failed
  1168. // for some reason, we should still do the copy for the values in this key.
  1169. //
  1170. //
  1171. // Enumerate all values in the source key and create all the values
  1172. // in the destination key
  1173. //
  1174. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) ValueBuffer;
  1175. for( Index = 0; ; Index++ )
  1176. {
  1177. // Zero the buffer in between each iteration.
  1178. //
  1179. RtlZeroMemory( ValueBuffer, sizeof(ValueBuffer) );
  1180. Status = NtEnumerateValueKey( hKeySrc, Index, KeyValueFullInformation, ValueBuffer, sizeof( ValueBuffer ), &ResultLength );
  1181. if ( !NT_SUCCESS(Status) )
  1182. {
  1183. if ( Status == STATUS_NO_MORE_ENTRIES )
  1184. {
  1185. Status = STATUS_SUCCESS;
  1186. }
  1187. else
  1188. {
  1189. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - failed to enumerate src value keys." );
  1190. }
  1191. break;
  1192. }
  1193. //
  1194. // Zero-terminate the subkey name just in case, init the
  1195. // unicode string and restore the wchar we whacked.
  1196. //
  1197. //
  1198. // ISSUE-2002/03/11-acosma - This is really funky. If we have a non-NULL terminated
  1199. // string we will end up with a UnicodeString that is not NULL terminated and has an extra
  1200. // character at the end. Maybe we should just increase the size of it by one to use the
  1201. // space where NULL should be as part of the string.
  1202. //
  1203. TmpChar = ValueInfo->Name[ValueInfo->NameLength/sizeof(WCHAR)];
  1204. ValueInfo->Name[ValueInfo->NameLength/sizeof(WCHAR)] = 0;
  1205. RtlInitUnicodeString( &UnicodeStringValue, ValueInfo->Name );
  1206. ValueInfo->Name[ValueInfo->NameLength/sizeof(WCHAR)] = TmpChar;
  1207. //
  1208. // Create the destination value.
  1209. //
  1210. Status = NtSetValueKey( hKeyDst,
  1211. &UnicodeStringValue,
  1212. ValueInfo->TitleIndex,
  1213. ValueInfo->Type,
  1214. (PBYTE)ValueInfo + ValueInfo->DataOffset,
  1215. ValueInfo->DataLength );
  1216. if( !NT_SUCCESS(Status) ) {
  1217. PRINT_STATUS( "SETUPCL: CopyKeyRecursive - failed to set destination value key." );
  1218. break;
  1219. }
  1220. }
  1221. return( Status );
  1222. }
  1223. NTSTATUS
  1224. CopyRegKey(
  1225. IN WCHAR *TargetName,
  1226. IN WCHAR *SourceName,
  1227. IN HANDLE hParentKey OPTIONAL
  1228. )
  1229. /*++
  1230. ===============================================================================
  1231. Routine Description:
  1232. Copy a registry key (and all its subkeys) to a new key.
  1233. Arguments:
  1234. TargetName - The name of the new key we're going to create.
  1235. SourceName - The name of the key we're copying.
  1236. Return Value:
  1237. NTSTATUS.
  1238. ===============================================================================
  1239. --*/
  1240. {
  1241. NTSTATUS Status = STATUS_SUCCESS;
  1242. HANDLE hKeySrc,
  1243. hKeyDst;
  1244. UNICODE_STRING UnicodeString;
  1245. OBJECT_ATTRIBUTES ObjaSrc,
  1246. ObjaDst;
  1247. ULONG BufferLength,
  1248. ResultLength;
  1249. PSECURITY_DESCRIPTOR pSD = NULL;
  1250. // Generate key handle for source key.
  1251. //
  1252. INIT_OBJA( &ObjaSrc, &UnicodeString, SourceName );
  1253. if ( hParentKey )
  1254. {
  1255. ObjaSrc.RootDirectory = hParentKey;
  1256. }
  1257. Status = NtOpenKey( &hKeySrc, KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY, &ObjaSrc );
  1258. if ( NT_SUCCESS( Status ) )
  1259. {
  1260. // Find out how big the descriptor is.
  1261. //
  1262. Status = NtQuerySecurityObject( hKeySrc, ALL_SECURITY_INFORMATION, NULL, 0, &BufferLength );
  1263. if ( Status == STATUS_BUFFER_TOO_SMALL )
  1264. {
  1265. // Allocate the buffer for the security descriptor.
  1266. //
  1267. if ( pSD = (PSECURITY_DESCRIPTOR)RtlAllocateHeap( RtlProcessHeap(), 0, BufferLength ) )
  1268. {
  1269. // Load the security info into the buffer.
  1270. //
  1271. Status = NtQuerySecurityObject( hKeySrc, ALL_SECURITY_INFORMATION, pSD, BufferLength, &ResultLength );
  1272. }
  1273. else
  1274. {
  1275. Status = STATUS_NO_MEMORY;
  1276. }
  1277. }
  1278. else
  1279. {
  1280. TEST_STATUS( "SETUPCL: CopyRegKey - Failed to query object security for size.");
  1281. }
  1282. if ( NT_SUCCESS(Status) )
  1283. {
  1284. INIT_OBJA( &ObjaDst, &UnicodeString, TargetName );
  1285. ObjaDst.SecurityDescriptor = pSD;
  1286. if ( hParentKey )
  1287. {
  1288. ObjaDst.RootDirectory = hParentKey;
  1289. }
  1290. // Create the destination key.
  1291. //
  1292. Status = NtCreateKey( &hKeyDst,
  1293. KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY,
  1294. &ObjaDst,
  1295. 0,
  1296. NULL,
  1297. REG_OPTION_NON_VOLATILE,
  1298. NULL );
  1299. if ( NT_SUCCESS(Status) )
  1300. {
  1301. Status = CopyKeyRecursive( hKeyDst, hKeySrc );
  1302. // Close the destination key.
  1303. //
  1304. NtClose( hKeyDst );
  1305. }
  1306. else
  1307. {
  1308. PRINT_STATUS( "SETUPCL: CopyRegKey - Failed to create destination key.");
  1309. }
  1310. }
  1311. else
  1312. {
  1313. PRINT_STATUS("SETUPCL: CopyRegKey - Failed to get key security descriptor.");
  1314. }
  1315. // If we allocated a buffer for the security descriptor, free it now.
  1316. //
  1317. if ( pSD )
  1318. {
  1319. RtlFreeHeap( RtlProcessHeap(), 0, pSD );
  1320. pSD = NULL;
  1321. }
  1322. // Close the source key.
  1323. //
  1324. NtClose( hKeySrc );
  1325. }
  1326. else
  1327. {
  1328. PRINT_STATUS( "SETUPCL: CopyRegKey - Failed to open source key." );
  1329. }
  1330. return( Status );
  1331. }
  1332. //
  1333. // ISSUE-2002/02/26-brucegr,jcohen - Dead Code! Nobody calls MoveRegKey!
  1334. //
  1335. NTSTATUS
  1336. MoveRegKey(
  1337. IN WCHAR *TargetName,
  1338. IN WCHAR *SourceName
  1339. )
  1340. /*++
  1341. ===============================================================================
  1342. Routine Description:
  1343. Move a registry key (and all its subkeys) to a new key.
  1344. Arguments:
  1345. TargetName - The name of the new key we're going to create.
  1346. SourceName - The name of the key we're copying.
  1347. Return Value:
  1348. NTSTATUS.
  1349. ===============================================================================
  1350. --*/
  1351. {
  1352. NTSTATUS Status;
  1353. //
  1354. // Copy the original..
  1355. //
  1356. Status = CopyRegKey( TargetName, SourceName, NULL );
  1357. TEST_STATUS_RETURN( "SETUPCL: MoveRegKey - CopyRegKey failed!" );
  1358. //
  1359. // Delete the original key.
  1360. //
  1361. Status = DeleteKey( SourceName );
  1362. TEST_STATUS( "SETUPCL: MoveRegKey - DeleteKey failed!" );
  1363. return( Status );
  1364. }
  1365. NTSTATUS
  1366. FindAndReplaceBlock(
  1367. IN PCHAR Block,
  1368. IN ULONG BlockLength,
  1369. IN PCHAR OldValue,
  1370. IN PCHAR NewValue,
  1371. IN ULONG ValueLength
  1372. )
  1373. /*++
  1374. ===============================================================================
  1375. Routine Description:
  1376. This function will go search Block for any and all instances of OldValue.
  1377. If he finds one, he'll replace that section with NewValue.
  1378. Arguments:
  1379. Block - A block of memory that we'll be searching
  1380. BlockLength - How big is Block
  1381. OldValue - What value are we looking for?
  1382. NewValue - What's the new value we'll be inserting?
  1383. ValueLength - How long are the Old and New values?
  1384. Return Value:
  1385. NTSTATUS.
  1386. ===============================================================================
  1387. --*/
  1388. {
  1389. ULONG i;
  1390. BOOLEAN We_Hit = FALSE;
  1391. //
  1392. // Make sure the lengths make sense... If not, we're done.
  1393. //
  1394. if( BlockLength < ValueLength ) {
  1395. #if 0
  1396. DbgPrint( "SETUPCL: FindAndReplaceBlock - Mismatched data lengths!\n\tBlockLength: (%lx)\n\tValueLength: (%lx)\n", BlockLength, ValueLength );
  1397. #endif
  1398. return( STATUS_UNSUCCESSFUL );
  1399. }
  1400. //
  1401. // We start at the beginning and search for any instances of OldValue.
  1402. //
  1403. i = 0;
  1404. while( i <= (BlockLength - ValueLength) ) {
  1405. if( !memcmp( (Block + i), OldValue, ValueLength ) ) {
  1406. //
  1407. // Record that we hit at least once.
  1408. //
  1409. We_Hit = TRUE;
  1410. //
  1411. // We got a hit. Insert NewValue.
  1412. //
  1413. memcpy( (Block + i), NewValue, ValueLength );
  1414. //
  1415. // Let's skip checking this block. We're asking for trouble
  1416. // if we don't.
  1417. //
  1418. i = i + ValueLength;
  1419. } else {
  1420. i++;
  1421. }
  1422. }
  1423. if( !We_Hit ) {
  1424. //
  1425. // We didn't find a match. It's likely non-fatal,
  1426. // but we need to tell our caller.
  1427. //
  1428. #if 0
  1429. DbgPrint( "SETUPCL: FindAndReplaceBlock - We didn't find any hits in this data block.\n" );
  1430. #endif
  1431. return( STATUS_UNSUCCESSFUL );
  1432. } else {
  1433. #if 0
  1434. DbgPrint( "SETUPCL: FindAndReplaceBlock - We hit in this data block.\n" );
  1435. #endif
  1436. return( STATUS_SUCCESS );
  1437. }
  1438. }
  1439. NTSTATUS
  1440. StringSwitchString(
  1441. PWSTR BaseString,
  1442. DWORD cBaseStringLen,
  1443. PWSTR OldSubString,
  1444. PWSTR NewSubString
  1445. )
  1446. /*++
  1447. ===============================================================================
  1448. Routine Description:
  1449. This function search BaseString for any instance of OldSubString. If
  1450. found, he'll replace that instance with NewSubString. Note that
  1451. OldSubString and NewSubString can be different lengths.
  1452. Arguments:
  1453. BaseString - This is the string we'll be operating on.
  1454. OldSubString - String we're looking for
  1455. NewSubString - String we'll be inserting
  1456. Return Value:
  1457. NTSTATUS.
  1458. ===============================================================================
  1459. --*/
  1460. {
  1461. NTSTATUS Status = STATUS_SUCCESS;
  1462. PWSTR Index;
  1463. WCHAR New_String[MAX_PATH] = {0};
  1464. WCHAR TmpChar;
  1465. Index = wcsstr( BaseString, OldSubString );
  1466. if( !Index ) {
  1467. //
  1468. // OldSubString isn't present.
  1469. //
  1470. return( STATUS_UNSUCCESSFUL );
  1471. }
  1472. //
  1473. // Copy the first part of the original string into New_String.
  1474. //
  1475. TmpChar = *Index;
  1476. *Index = 0;
  1477. wcsncpy( New_String, BaseString, AS(New_String) - 1 );
  1478. //
  1479. // Now concatenate the new sub string...
  1480. //
  1481. wcsncpy( New_String + wcslen(New_String), NewSubString, AS(New_String) - wcslen(New_String) - 1 );
  1482. //
  1483. // Jump past the OldSubString, and cat the remaining BaseString
  1484. // onto the end.
  1485. //
  1486. Index = Index + wcslen( OldSubString );
  1487. wcsncpy( New_String + wcslen(New_String), Index, AS(New_String) - wcslen(New_String) - 1);
  1488. memset( BaseString, 0, cBaseStringLen * sizeof(WCHAR) );
  1489. wcsncpy( BaseString, New_String, cBaseStringLen - 1 );
  1490. return( STATUS_SUCCESS );
  1491. }
  1492. NTSTATUS
  1493. SiftKeyRecursive(
  1494. HANDLE hKey,
  1495. int indent
  1496. )
  1497. /*++
  1498. ===============================================================================
  1499. Routine Description:
  1500. This function check all of the subkeys and any valuekeys for:
  1501. - keys with the old SID name
  1502. In this case, we rename the key with the appropriate new SID name.
  1503. - value keys with the old SID value
  1504. In this case, we substitute the new SID values for the old SID values.
  1505. Arguments:
  1506. hKey - Handle to the key we're about to recurse into.
  1507. indent - For debug. Number of spaces to indent any messages.
  1508. This helps us determine which recurse we're in.
  1509. Return Value:
  1510. NTSTATUS.
  1511. ===============================================================================
  1512. --*/
  1513. {
  1514. NTSTATUS Status = STATUS_SUCCESS;
  1515. OBJECT_ATTRIBUTES Obja;
  1516. UNICODE_STRING UnicodeString;
  1517. HANDLE hKeyChild;
  1518. ULONG ResultLength, Index;
  1519. PKEY_BASIC_INFORMATION KeyInfo;
  1520. PKEY_VALUE_BASIC_INFORMATION ValueInfo;
  1521. int i;
  1522. // DisplayUI
  1523. //
  1524. DisplayUI();
  1525. //
  1526. // Enumerate all keys in the source key and recursively create
  1527. // all the subkeys
  1528. //
  1529. KeyInfo = (PKEY_BASIC_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
  1530. 0,
  1531. BASIC_INFO_BUFFER_SIZE );
  1532. if( KeyInfo == NULL ) {
  1533. #if I_AM_MATTH
  1534. DbgPrint( "SETUPCL: SiftKeyRecursive - Call to RtlAllocateHeap failed!\n" );
  1535. #endif
  1536. return( STATUS_NO_MEMORY );
  1537. }
  1538. Index = 0;
  1539. while( 1 ) {
  1540. Status = NtEnumerateKey( hKey,
  1541. Index,
  1542. KeyBasicInformation,
  1543. KeyInfo,
  1544. BASIC_INFO_BUFFER_SIZE,
  1545. &ResultLength );
  1546. if(!NT_SUCCESS(Status)) {
  1547. if(Status == STATUS_NO_MORE_ENTRIES) {
  1548. Status = STATUS_SUCCESS;
  1549. } else {
  1550. TEST_STATUS( "SETUPCL: SiftKeyRecursive - Failure during enumeration of subkeys." );
  1551. }
  1552. break;
  1553. }
  1554. //
  1555. // Zero-terminate the subkey name just in case.
  1556. //
  1557. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  1558. memset( TmpBuffer, 0, sizeof(TmpBuffer) );
  1559. wcsncpy( TmpBuffer, KeyInfo->Name, AS(TmpBuffer) - 1 );
  1560. Status = StringSwitchString( TmpBuffer,
  1561. AS( TmpBuffer ),
  1562. G_OldSidSubString,
  1563. G_NewSidSubString );
  1564. if( NT_SUCCESS( Status ) ) {
  1565. //
  1566. // We need to rename this key. First do the
  1567. // copy, then a delete.
  1568. //
  1569. #if I_AM_MATTH
  1570. for( i = 0; i < indent; i++ )
  1571. DbgPrint( " " );
  1572. DbgPrint( "SETUPCL: SiftKeyRecursive - About to copy subkey:\n" );
  1573. DbgPrint( "\t%ws\n\tto\n\t%ws\n", KeyInfo->Name, TmpBuffer );
  1574. #endif
  1575. Status = CopyRegKey( TmpBuffer,
  1576. KeyInfo->Name,
  1577. hKey );
  1578. if( !NT_SUCCESS( Status ) ) {
  1579. TEST_STATUS( "SETUPCL: SiftKeyRecursive - failed call to CopyRegKey." );
  1580. break;
  1581. }
  1582. DeleteKeyRecursive( hKey, KeyInfo->Name );
  1583. // Flush the key to make sure that everything gets written out to disk.
  1584. //
  1585. NtFlushKey(hKey);
  1586. //
  1587. // Now reset our index since we've just changed the ordering
  1588. // of keys.
  1589. //
  1590. Index = 0;
  1591. continue;
  1592. }
  1593. //
  1594. // We didn't rename him, so let's recursively call ourselves
  1595. // on the subkey key.
  1596. //
  1597. #if I_AM_MATTH
  1598. for( i = 0; i < indent; i++ )
  1599. DbgPrint( " " );
  1600. DbgPrint( "SETUPCL: SiftKeyRecursive - About to check subkey: %ws\n",
  1601. KeyInfo->Name );
  1602. #endif
  1603. //
  1604. // Generate a handle for this child key and call ourselves again.
  1605. //
  1606. INIT_OBJA( &Obja, &UnicodeString, KeyInfo->Name );
  1607. Obja.RootDirectory = hKey;
  1608. Status = NtOpenKey( &hKeyChild,
  1609. KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY,
  1610. &Obja );
  1611. TEST_STATUS_RETURN( "SETUPCL: SiftKeyRecursive - Failed to open child key." );
  1612. Status = SiftKeyRecursive( hKeyChild, indent + 1 );
  1613. NtClose( hKeyChild );
  1614. Index++;
  1615. }
  1616. //
  1617. // Enumerate all values in the key and search for instances
  1618. // of the old SID.
  1619. //
  1620. ValueInfo = (PKEY_VALUE_BASIC_INFORMATION)KeyInfo;
  1621. for( Index = 0; ; Index++ ) {
  1622. Status = NtEnumerateValueKey( hKey,
  1623. Index,
  1624. KeyValueBasicInformation,
  1625. ValueInfo,
  1626. BASIC_INFO_BUFFER_SIZE,
  1627. &ResultLength );
  1628. if(!NT_SUCCESS(Status)) {
  1629. if(Status == STATUS_NO_MORE_ENTRIES) {
  1630. Status = STATUS_SUCCESS;
  1631. } else {
  1632. TEST_STATUS( "SETUPCL: SiftKeyRecursive - Failure during enumeration of value keys." );
  1633. }
  1634. break;
  1635. }
  1636. //
  1637. // Zero-terminate the subkey name just in case.
  1638. //
  1639. ValueInfo->Name[ValueInfo->NameLength/sizeof(WCHAR)] = 0;
  1640. //
  1641. // ISSUE - 2002/03/01-brucegr,acosma: We don't handle value names containing the old SID.
  1642. //
  1643. //
  1644. // We'll probably fail this call because the key probably
  1645. // doesn't contain any SID info. For that reason, don't
  1646. // treat failures here as fatal...
  1647. //
  1648. if( ValueInfo->Type == REG_SZ ) {
  1649. //
  1650. // ISSUE - 2002/03/01-brucegr,acosma: We should handle REG_MULTI_SZ like a string instead of binary data
  1651. //
  1652. Status = ReadSetWriteKey( NULL, // No parent Name.
  1653. hKey, // Parent handle.
  1654. ValueInfo->Name, // SubKey name
  1655. (PUCHAR)G_OldSidSubString,
  1656. (PUCHAR)G_NewSidSubString,
  1657. 0xC,
  1658. ValueInfo->Type );
  1659. } else {
  1660. Status = ReadSetWriteKey( NULL, // No parent Name.
  1661. hKey, // Parent handle.
  1662. ValueInfo->Name, // SubKey name
  1663. (PUCHAR)G_OldSid + (SID_SIZE - 0xC),
  1664. (PUCHAR)G_NewSid + (SID_SIZE - 0xC),
  1665. 0xC,
  1666. ValueInfo->Type );
  1667. }
  1668. #if I_AM_MATTH
  1669. if( NT_SUCCESS( Status ) ) {
  1670. for( i = 0; i < indent; i++ )
  1671. DbgPrint( " " );
  1672. DbgPrint( "SETUPCL: SiftKeyRecursive - updated subkey: %ws\n",
  1673. ValueInfo->Name );
  1674. #if 0
  1675. } else {
  1676. for( i = 0; i < indent; i++ )
  1677. DbgPrint( " " );
  1678. DbgPrint( "SETUPCL: SiftKeyRecursive - did not update subkey: %ws\n",
  1679. ValueInfo->Name );
  1680. #endif
  1681. }
  1682. #endif
  1683. }
  1684. RtlFreeHeap( RtlProcessHeap(),
  1685. 0,
  1686. KeyInfo );
  1687. return( Status );
  1688. }
  1689. NTSTATUS
  1690. SiftKey(
  1691. PWSTR KeyName
  1692. )
  1693. /*++
  1694. ===============================================================================
  1695. Routine Description:
  1696. This function opens a handle to the key specified in KeyName, the
  1697. calls SiftKeyRecursive with it.
  1698. Arguments:
  1699. KeyName - Name of the key we're about to operate on.
  1700. Return Value:
  1701. NTSTATUS.
  1702. ===============================================================================
  1703. --*/
  1704. {
  1705. NTSTATUS Status = STATUS_SUCCESS;
  1706. HANDLE hKey;
  1707. UNICODE_STRING UnicodeString;
  1708. OBJECT_ATTRIBUTES Obja;
  1709. //
  1710. // Open the key.
  1711. //
  1712. INIT_OBJA( &Obja, &UnicodeString, KeyName );
  1713. Status = NtOpenKey( &hKey,
  1714. KEY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY,
  1715. &Obja );
  1716. TEST_STATUS( "SETUPCL: SiftKey - Failed to open key." );
  1717. //
  1718. // Fix all instances of the SID in this key and all
  1719. // it's children.
  1720. //
  1721. Status = SiftKeyRecursive( hKey, 0 );
  1722. //
  1723. // Now fix ACLs on this key and all its children.
  1724. //
  1725. SetKeySecurityRecursive( hKey );
  1726. NtClose( hKey );
  1727. return( Status );
  1728. }
  1729. NTSTATUS
  1730. DriveLetterToNTPath(
  1731. IN WCHAR DriveLetter,
  1732. IN OUT PWSTR NTPath,
  1733. IN DWORD cNTPathLen
  1734. )
  1735. /*++
  1736. ===============================================================================
  1737. Routine Description:
  1738. This function will convert a driveletter to an NT path.
  1739. Arguments:
  1740. DriveLetter - DriveLetter.
  1741. NTPath - The ntpath that corresponds to the given drive letter.
  1742. Return Value:
  1743. NTSTATUS.
  1744. ===============================================================================
  1745. --*/
  1746. {
  1747. NTSTATUS Status = STATUS_SUCCESS;
  1748. OBJECT_ATTRIBUTES ObjectAttributes;
  1749. HANDLE DosDevicesDir,
  1750. Handle;
  1751. CHAR DirInfoBuffer[1024],
  1752. LinkTargetBuffer[1024];
  1753. POBJECT_DIRECTORY_INFORMATION DirInfo;
  1754. UNICODE_STRING UnicodeString,
  1755. LinkTarget,
  1756. DesiredPrefix1,
  1757. DesiredPrefix2,
  1758. LinkTypeName;
  1759. ULONG Context,
  1760. Length;
  1761. //
  1762. // Open \DosDevices
  1763. //
  1764. RtlInitUnicodeString(&UnicodeString,L"\\DosDevices");
  1765. InitializeObjectAttributes(
  1766. &ObjectAttributes,
  1767. &UnicodeString,
  1768. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  1769. NULL,
  1770. NULL
  1771. );
  1772. Status = NtOpenDirectoryObject(&DosDevicesDir,DIRECTORY_QUERY,&ObjectAttributes);
  1773. TEST_STATUS_RETURN( "SETUPCL: DriveLetterToNTPath - Failed to open DosDevices." );
  1774. LinkTarget.Buffer = (PVOID)LinkTargetBuffer;
  1775. RtlInitUnicodeString(&LinkTypeName,L"SymbolicLink");
  1776. DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
  1777. //
  1778. // Query first object in \DosDevices directory
  1779. //
  1780. Status = NtQueryDirectoryObject( DosDevicesDir,
  1781. DirInfo,
  1782. sizeof(DirInfoBuffer),
  1783. TRUE,
  1784. TRUE,
  1785. &Context,
  1786. &Length );
  1787. while(NT_SUCCESS(Status)) {
  1788. //
  1789. // Terminate these guys just in case...
  1790. //
  1791. DirInfo->Name.Buffer[DirInfo->Name.Length/sizeof(WCHAR)] = 0;
  1792. DirInfo->TypeName.Buffer[DirInfo->TypeName.Length/sizeof(WCHAR)] = 0;
  1793. // DbgPrint( "SETUPCL: DriveLetterToNTPath - About to examine an object: %ws\n", DirInfo->Name.Buffer );
  1794. //
  1795. // Make sure he's a drive letter.
  1796. // Make sure he's our drive letter.
  1797. // Make sure he's a symbolic link.
  1798. //
  1799. if( (DirInfo->Name.Buffer[1] == L':') &&
  1800. (DirInfo->Name.Buffer[0] == DriveLetter) &&
  1801. (RtlEqualUnicodeString(&LinkTypeName,&DirInfo->TypeName,TRUE)) ) {
  1802. // DbgPrint( "\tSETUPCL: DriveLetterToNTPath - Object: %ws is a symbolic link\n", DirInfo->Name.Buffer );
  1803. InitializeObjectAttributes(
  1804. &ObjectAttributes,
  1805. &DirInfo->Name,
  1806. OBJ_CASE_INSENSITIVE,
  1807. DosDevicesDir,
  1808. NULL
  1809. );
  1810. Status = NtOpenSymbolicLinkObject( &Handle,
  1811. SYMBOLIC_LINK_ALL_ACCESS,
  1812. &ObjectAttributes );
  1813. if(NT_SUCCESS(Status)) {
  1814. LinkTarget.Length = 0;
  1815. LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
  1816. Status = NtQuerySymbolicLinkObject( Handle,
  1817. &LinkTarget,
  1818. NULL );
  1819. NtClose(Handle);
  1820. TEST_STATUS( "\tSETUPCL: DriveLetterToNTPath - We failed to queried him.\n" );
  1821. LinkTarget.Buffer[LinkTarget.Length/sizeof(WCHAR)] = 0;
  1822. // DbgPrint( "\tSETUPCL: DriveLetterToNTPath - We queried him and his name is %ws.\n", LinkTarget.Buffer );
  1823. //
  1824. // Copy the buffer into out our path and break from the loop.
  1825. //
  1826. //
  1827. // NTRAID#NTBUG9-545988-2002/02/26-brucegr,jcohen - Buffer overrun
  1828. //
  1829. memset( NTPath, 0, cNTPathLen * sizeof(WCHAR) );
  1830. wcsncpy( NTPath, LinkTarget.Buffer, cNTPathLen - 1 );
  1831. break;
  1832. }
  1833. }
  1834. //
  1835. // Query next object in \DosDevices directory
  1836. //
  1837. Status = NtQueryDirectoryObject( DosDevicesDir,
  1838. DirInfo,
  1839. sizeof(DirInfoBuffer),
  1840. TRUE,
  1841. FALSE,
  1842. &Context,
  1843. &Length );
  1844. }
  1845. NtClose(DosDevicesDir);
  1846. return( STATUS_SUCCESS );
  1847. }
  1848. // If there are any problems with the Japanese build see nt\base\fs\utils\ulib\src\basesys.cxx, around line 150
  1849. // to see what they did.
  1850. BOOL LoadStringResource(
  1851. PUNICODE_STRING pUnicodeString,
  1852. INT MsgId
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. This is a simple implementation of LoadString().
  1857. Arguments:
  1858. usString - Returns the resource string.
  1859. MsgId - Supplies the message id of the resource string.
  1860. Return Value:
  1861. FALSE - Failure.
  1862. TRUE - Success.
  1863. --*/
  1864. {
  1865. NTSTATUS Status;
  1866. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  1867. ANSI_STRING AnsiString;
  1868. Status = RtlFindMessage( NtCurrentPeb()->ImageBaseAddress,
  1869. (ULONG_PTR) RT_MESSAGETABLE,
  1870. 0,
  1871. (ULONG)MsgId,
  1872. &MessageEntry
  1873. );
  1874. if (!NT_SUCCESS( Status )) {
  1875. return FALSE;
  1876. }
  1877. if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
  1878. RtlInitAnsiString( &AnsiString, (PCSZ)&MessageEntry->Text[ 0 ] );
  1879. Status = RtlAnsiStringToUnicodeString( pUnicodeString, &AnsiString, TRUE );
  1880. if (!NT_SUCCESS( Status )) {
  1881. return FALSE;
  1882. }
  1883. } else {
  1884. //
  1885. // ISSUE-2002/02/26-brucegr,jcohen - Doesn't check return code from RtlCreateUnicodeString
  1886. //
  1887. RtlCreateUnicodeString(pUnicodeString, (PWSTR)MessageEntry->Text);
  1888. }
  1889. return TRUE;
  1890. }