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.

3434 lines
103 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. regtool.c
  5. Abstract:
  6. This file contains functions for supporting the registry tools
  7. REGINI, REGDMP, REGDIR and REGFIND
  8. Author:
  9. Steve Wood (stevewo) 15-Nov-1995
  10. Revision History:
  11. --*/
  12. #include <tchar.h>
  13. #include "regutil.h"
  14. ULONG ValueBufferSize = (4096 * 100);
  15. PVOID ValueBuffer;
  16. UCHAR BlanksForPadding[] =
  17. " ";
  18. //
  19. // routines for creating security descriptors (defined in regacl.c)
  20. //
  21. BOOLEAN
  22. RegInitializeSecurity(
  23. VOID
  24. );
  25. BOOLEAN
  26. WINAPI
  27. RegUnicodeToDWORD(
  28. IN OUT PWSTR *String,
  29. IN DWORD Base OPTIONAL,
  30. OUT PDWORD Value
  31. );
  32. BOOLEAN
  33. RegCreateSecurity(
  34. IN PWSTR Description,
  35. OUT PSECURITY_DESCRIPTOR SecurityDescriptor
  36. );
  37. BOOLEAN
  38. RegFormatSecurity(
  39. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  40. OUT PWSTR AceList
  41. );
  42. VOID
  43. RegDestroySecurity(
  44. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  45. );
  46. LONG
  47. RegLoadHive(
  48. IN PREG_CONTEXT RegistryContext,
  49. IN PWSTR HiveFileName,
  50. IN PWSTR HiveRootName
  51. );
  52. void
  53. RegUnloadHive(
  54. IN PREG_CONTEXT RegistryContext
  55. );
  56. struct {
  57. PWSTR TypeName;
  58. ULONG ValueType;
  59. BOOLEAN GetDataFromBinaryFile;
  60. BOOLEAN GetDataFromMultiSzFile;
  61. BOOLEAN ParseDateTime;
  62. } RegTypeNameTable[] = {
  63. {L"REG_SZ", REG_SZ, FALSE, FALSE, FALSE},
  64. {L"REG_EXPAND_SZ", REG_EXPAND_SZ, FALSE, FALSE, FALSE},
  65. {L"REG_MULTI_SZ", REG_MULTI_SZ, FALSE, FALSE, FALSE},
  66. {L"REG_MULTISZ_FILE", REG_MULTI_SZ, FALSE, TRUE, FALSE},
  67. {L"REG_DWORD", REG_DWORD, FALSE, FALSE, FALSE},
  68. {L"REG_NONE", REG_NONE, FALSE, FALSE, FALSE},
  69. {L"REG_BINARY", REG_BINARY, FALSE, FALSE, FALSE},
  70. {L"REG_BINARYFILE", REG_BINARY, TRUE, FALSE, FALSE},
  71. {L"REG_DATE", REG_BINARY, FALSE, FALSE, TRUE},
  72. {L"REG_RESOURCE_LIST", REG_RESOURCE_LIST, FALSE, FALSE, FALSE},
  73. {L"REG_RESOURCE_REQUIREMENTS_LIST", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE},
  74. {L"REG_RESOURCE_REQUIREMENTS", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE},
  75. {L"REG_FULL_RESOURCE_DESCRIPTOR", REG_FULL_RESOURCE_DESCRIPTOR, FALSE, FALSE, FALSE},
  76. {NULL, REG_NONE, FALSE, FALSE, FALSE}
  77. };
  78. struct {
  79. PWSTR ValueName;
  80. ULONG Value;
  81. } RegValueNameTable[] = {
  82. {L"ON", TRUE},
  83. {L"YES", TRUE},
  84. {L"TRUE", TRUE},
  85. {L"OFF", FALSE},
  86. {L"NO", FALSE},
  87. {L"FALSE", FALSE},
  88. {NULL, FALSE}
  89. };
  90. int
  91. RegAnsiToUnicode(
  92. LPCSTR Source,
  93. PWSTR Destination,
  94. ULONG NumberOfChars
  95. )
  96. {
  97. int NumberOfXlatedChars;
  98. if (NumberOfChars == 0) {
  99. NumberOfChars = strlen( Source );
  100. }
  101. NumberOfXlatedChars = MultiByteToWideChar( CP_ACP,
  102. MB_PRECOMPOSED,
  103. Source,
  104. NumberOfChars,
  105. Destination,
  106. NumberOfChars
  107. );
  108. Destination[ NumberOfXlatedChars ] = UNICODE_NULL;
  109. if ( NumberOfXlatedChars == 0 ) {
  110. SetLastError( ERROR_NO_UNICODE_TRANSLATION );
  111. }
  112. return NumberOfXlatedChars;
  113. }
  114. int
  115. RegUnicodeToAnsi(
  116. PCWSTR Source,
  117. LPSTR Destination,
  118. ULONG NumberOfChars
  119. )
  120. {
  121. int NumberOfXlatedChars;
  122. if (NumberOfChars == 0) {
  123. NumberOfChars = wcslen( Source );
  124. }
  125. NumberOfXlatedChars = WideCharToMultiByte( CP_ACP,
  126. 0,
  127. Source,
  128. NumberOfChars,
  129. Destination,
  130. NumberOfChars * 2,
  131. NULL,
  132. NULL
  133. );
  134. Destination[ NumberOfXlatedChars ] = '\0';
  135. if ( NumberOfXlatedChars == 0 ) {
  136. SetLastError( ERROR_NO_UNICODE_TRANSLATION );
  137. }
  138. return NumberOfXlatedChars;
  139. }
  140. typedef
  141. LONG
  142. (APIENTRY *LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)(
  143. HKEY hKey,
  144. LPCSTR lpFileName,
  145. UINT Flags
  146. );
  147. typedef
  148. LONG
  149. (APIENTRY *LPVMMREGLOADKEY_PROCEDURE)(
  150. HKEY hKey,
  151. LPCSTR lpSubKey,
  152. LPCSTR lpFileName
  153. );
  154. typedef
  155. LONG
  156. (APIENTRY *LPVMMREGUNLOADKEY_PROCEDURE)(
  157. HKEY hKey,
  158. LPCSTR lpSubKey
  159. );
  160. typedef
  161. LONG
  162. (APIENTRY *LPVMMREGCREATEKEY_PROCEDURE)(
  163. HKEY hKey,
  164. LPCSTR lpSubKey,
  165. PHKEY lphSubKey
  166. );
  167. typedef
  168. LONG
  169. (APIENTRY *LPVMMREGDELETEKEY_PROCEDURE)(
  170. HKEY hKey,
  171. LPCSTR lpSubKey
  172. );
  173. typedef
  174. LONG
  175. (APIENTRY *LPVMMREGOPENKEY_PROCEDURE)(
  176. HKEY hKey,
  177. LPCSTR lpSubKey,
  178. PHKEY lphSubKey
  179. );
  180. typedef
  181. LONG
  182. (APIENTRY *LPVMMREGFLUSHKEY_PROCEDURE)(
  183. HKEY hKey
  184. );
  185. typedef
  186. LONG
  187. (APIENTRY *LPVMMREGCLOSEKEY_PROCEDURE)(
  188. HKEY hKey
  189. );
  190. typedef
  191. LONG
  192. (APIENTRY *LPVMMREGQUERYINFOKEY_PROCEDURE)(
  193. HKEY hKey,
  194. LPCSTR lpClass,
  195. LPDWORD lpcbClass,
  196. LPDWORD lpReserved,
  197. LPDWORD lpcSubKeys,
  198. LPDWORD lpcbMaxSubKeyLen,
  199. LPDWORD lpcbMaxClassLen,
  200. LPDWORD lpcValues,
  201. LPDWORD lpcbMaxValueName,
  202. LPDWORD lpcbMaxValueData,
  203. LPVOID lpcbSecurityDescriptor,
  204. LPVOID lpftLastWriteTime
  205. );
  206. typedef
  207. LONG
  208. (APIENTRY *LPVMMREGENUMKEY_PROCEDURE)(
  209. HKEY hKey,
  210. DWORD Index,
  211. LPSTR lpKeyName,
  212. DWORD cbKeyName
  213. );
  214. typedef
  215. LONG
  216. (APIENTRY *LPVMMREGENUMVALUE_PROCEDURE)(
  217. HKEY hKey,
  218. DWORD Index,
  219. LPSTR lpValueName,
  220. LPDWORD lpcbValueName,
  221. LPDWORD lpReserved,
  222. LPDWORD lpType,
  223. LPBYTE lpData,
  224. LPDWORD lpcbData
  225. );
  226. typedef
  227. LONG
  228. (APIENTRY *LPVMMREGQUERYVALUEEX_PROCEDURE)(
  229. HKEY hKey,
  230. LPCSTR lpValueName,
  231. LPDWORD lpReserved,
  232. LPDWORD lpType,
  233. LPBYTE lpData,
  234. LPDWORD lpcbData
  235. );
  236. typedef
  237. LONG
  238. (APIENTRY *LPVMMREGSETVALUEEX_PROCEDURE)(
  239. HKEY hKey,
  240. LPCSTR lpValueName,
  241. DWORD Reserved,
  242. DWORD Type,
  243. LPBYTE lpData,
  244. DWORD cbData
  245. );
  246. typedef
  247. LONG
  248. (APIENTRY *LPVMMREGDELETEVALUE_PROCEDURE)(
  249. HKEY hKey,
  250. LPCSTR lpValueName
  251. );
  252. HMODULE hVMMREG32;
  253. LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE _Win95RegMapPredefKeyToFile;
  254. LPVMMREGLOADKEY_PROCEDURE _Win95RegLoadKey;
  255. LPVMMREGUNLOADKEY_PROCEDURE _Win95RegUnLoadKey;
  256. LPVMMREGCREATEKEY_PROCEDURE _Win95RegCreateKey;
  257. LPVMMREGDELETEKEY_PROCEDURE _Win95RegDeleteKey;
  258. LPVMMREGOPENKEY_PROCEDURE _Win95RegOpenKey;
  259. LPVMMREGFLUSHKEY_PROCEDURE _Win95RegFlushKey;
  260. LPVMMREGCLOSEKEY_PROCEDURE _Win95RegCloseKey;
  261. LPVMMREGQUERYINFOKEY_PROCEDURE _Win95RegQueryInfoKey;
  262. LPVMMREGENUMKEY_PROCEDURE _Win95RegEnumKey;
  263. LPVMMREGENUMVALUE_PROCEDURE _Win95RegEnumValue;
  264. LPVMMREGQUERYVALUEEX_PROCEDURE _Win95RegQueryValueEx;
  265. LPVMMREGSETVALUEEX_PROCEDURE _Win95RegSetValueEx;
  266. LPVMMREGDELETEVALUE_PROCEDURE _Win95RegDeleteValue;
  267. BOOLEAN
  268. RegInitWin95RegistryAccess(
  269. PREG_CONTEXT RegistryContext,
  270. PWSTR Win95Path,
  271. PWSTR Win95UserPath
  272. )
  273. {
  274. LONG Error;
  275. char Buffer[ MAX_PATH+1 ];
  276. if ((hVMMREG32 = LoadLibrary( L"VMMREG32" )) == NULL) {
  277. return FALSE;
  278. }
  279. _Win95RegMapPredefKeyToFile = (LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)GetProcAddress( hVMMREG32, "VMMRegMapPredefKeyToFile" );
  280. _Win95RegLoadKey = (LPVMMREGLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegLoadKey" );
  281. _Win95RegUnLoadKey = (LPVMMREGUNLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegUnLoadKey" );
  282. _Win95RegCreateKey = (LPVMMREGCREATEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCreateKey" );
  283. _Win95RegDeleteKey = (LPVMMREGDELETEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteKey" );
  284. _Win95RegOpenKey = (LPVMMREGOPENKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegOpenKey" );
  285. _Win95RegFlushKey = (LPVMMREGFLUSHKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegFlushKey" );
  286. _Win95RegCloseKey = (LPVMMREGCLOSEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCloseKey" );
  287. _Win95RegQueryInfoKey = (LPVMMREGQUERYINFOKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryInfoKey" );
  288. _Win95RegEnumKey = (LPVMMREGENUMKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumKey" );
  289. _Win95RegEnumValue = (LPVMMREGENUMVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumValue" );
  290. _Win95RegQueryValueEx = (LPVMMREGQUERYVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryValueEx" );
  291. _Win95RegSetValueEx = (LPVMMREGSETVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegSetValueEx" );
  292. _Win95RegDeleteValue = (LPVMMREGDELETEVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteValue" );
  293. if ((_Win95RegMapPredefKeyToFile == NULL) ||
  294. (_Win95RegLoadKey == NULL) ||
  295. (_Win95RegUnLoadKey == NULL) ||
  296. (_Win95RegCreateKey == NULL) ||
  297. (_Win95RegDeleteKey == NULL) ||
  298. (_Win95RegOpenKey == NULL) ||
  299. (_Win95RegFlushKey == NULL) ||
  300. (_Win95RegCloseKey == NULL) ||
  301. (_Win95RegQueryInfoKey == NULL) ||
  302. (_Win95RegEnumKey == NULL) ||
  303. (_Win95RegEnumValue == NULL) ||
  304. (_Win95RegQueryValueEx == NULL) ||
  305. (_Win95RegSetValueEx == NULL) ||
  306. (_Win95RegDeleteValue == NULL)
  307. ) {
  308. FreeLibrary( hVMMREG32 );
  309. SetLastError( ERROR_PROC_NOT_FOUND );
  310. return FALSE;
  311. }
  312. //
  313. // Map HKEY_LOCAL_MACHINE of Win95 hive
  314. //
  315. RegUnicodeToAnsi( Win95Path, Buffer, 0 );
  316. strcat( Buffer, "\\system.dat" );
  317. Error = (_Win95RegMapPredefKeyToFile)( HKEY_LOCAL_MACHINE, Buffer, 0 );
  318. if (Error == NO_ERROR) {
  319. RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
  320. RegUnicodeToAnsi( Win95Path, Buffer, 0 );
  321. strcat( Buffer, "\\user.dat" );
  322. Error = (_Win95RegMapPredefKeyToFile)( HKEY_USERS, Buffer, 0 );
  323. if (Error == NO_ERROR) {
  324. RegistryContext->UsersRoot = HKEY_USERS;
  325. Error = (_Win95RegOpenKey)( HKEY_USERS, ".Default", &RegistryContext->CurrentUserRoot );
  326. }
  327. }
  328. if (Error != NO_ERROR) {
  329. if (RegistryContext->MachineRoot != NULL) {
  330. (_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 );
  331. }
  332. if (RegistryContext->UsersRoot) {
  333. (_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 );
  334. }
  335. FreeLibrary( hVMMREG32 );
  336. SetLastError( Error );
  337. return FALSE;
  338. }
  339. wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
  340. wcscpy( RegistryContext->CurrentUserPath, RegistryContext->UsersPath );
  341. wcscat( RegistryContext->CurrentUserPath, L"\\.Default" );
  342. return TRUE;
  343. }
  344. BOOLEAN PrivilegeEnabled;
  345. BOOLEAN RestoreWasEnabled;
  346. BOOLEAN BackupWasEnabled;
  347. BOOLEAN
  348. RTEnableBackupRestorePrivilege( void )
  349. {
  350. NTSTATUS Status;
  351. //
  352. // Try to enable backup and restore privileges
  353. //
  354. Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  355. TRUE, // Enable
  356. FALSE, // Not impersonating
  357. &RestoreWasEnabled // previous state
  358. );
  359. if (!NT_SUCCESS( Status )) {
  360. return FALSE;
  361. }
  362. Status = RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
  363. TRUE, // Enable
  364. FALSE, // Not impersonating
  365. &BackupWasEnabled // previous state
  366. );
  367. if (!NT_SUCCESS( Status )) {
  368. return FALSE;
  369. }
  370. PrivilegeEnabled = TRUE;
  371. return TRUE;
  372. }
  373. void
  374. RTDisableBackupRestorePrivilege( void )
  375. {
  376. //
  377. // Restore privileges to what they were
  378. //
  379. RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  380. RestoreWasEnabled,
  381. FALSE,
  382. &RestoreWasEnabled
  383. );
  384. RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
  385. BackupWasEnabled,
  386. FALSE,
  387. &BackupWasEnabled
  388. );
  389. PrivilegeEnabled = FALSE;
  390. return;
  391. }
  392. BOOLEAN
  393. RTInitialize( void )
  394. /*++
  395. Routine Description:
  396. DLL initialization function.
  397. Arguments:
  398. hInstance - Instance handle
  399. Reason - Reason for the entrypoint being called
  400. Context - Context record
  401. Return Value:
  402. TRUE - Initialization succeeded
  403. FALSE - Initialization failed
  404. --*/
  405. {
  406. ValueBuffer = VirtualAlloc( NULL, ValueBufferSize, MEM_COMMIT, PAGE_READWRITE );
  407. if (ValueBuffer == NULL) {
  408. return FALSE;
  409. }
  410. if (!RegInitializeSecurity()) {
  411. return FALSE;
  412. }
  413. return TRUE;
  414. }
  415. LONG
  416. RTConnectToRegistry(
  417. IN PWSTR MachineName,
  418. IN PWSTR HiveFileName,
  419. IN PWSTR HiveRootName,
  420. IN PWSTR Win95Path,
  421. IN PWSTR Win95UserName,
  422. OUT PWSTR *DefaultRootKeyName,
  423. OUT PREG_CONTEXT RegistryContext
  424. )
  425. {
  426. LONG Error;
  427. if (MachineName != NULL) {
  428. if (HiveRootName || HiveFileName || Win95Path || Win95UserName) {
  429. return ERROR_INVALID_PARAMETER;
  430. }
  431. Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot );
  432. if (Error == NO_ERROR) {
  433. Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot );
  434. if (Error == NO_ERROR) {
  435. Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot );
  436. }
  437. }
  438. if (Error != NO_ERROR) {
  439. if (RegistryContext->MachineRoot != NULL) {
  440. RegCloseKey( RegistryContext->MachineRoot );
  441. RegistryContext->MachineRoot = NULL;
  442. }
  443. if (RegistryContext->UsersRoot != NULL) {
  444. RegCloseKey( RegistryContext->UsersRoot );
  445. RegistryContext->UsersRoot = NULL;
  446. }
  447. return Error;
  448. }
  449. wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
  450. wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
  451. wcscpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default" );
  452. RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY;
  453. }
  454. else
  455. if (HiveRootName != NULL || HiveFileName != NULL) {
  456. if (HiveRootName == NULL || HiveFileName == NULL ||
  457. Win95Path != NULL || Win95UserName != NULL
  458. ) {
  459. return ERROR_INVALID_PARAMETER;
  460. }
  461. if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) {
  462. return ERROR_PRIVILEGE_NOT_HELD;
  463. }
  464. RegistryContext->MachineRoot = NULL;
  465. RegistryContext->UsersRoot = NULL;
  466. RegistryContext->CurrentUserRoot = NULL;
  467. Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName );
  468. if (Error != NO_ERROR) {
  469. return Error;
  470. }
  471. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  472. *DefaultRootKeyName = HiveRootName;
  473. }
  474. RegistryContext->Target = REG_TARGET_HIVE_REGISTRY;
  475. }
  476. else
  477. if (Win95Path != NULL || Win95UserName != NULL) {
  478. if (!RegInitWin95RegistryAccess( RegistryContext,
  479. Win95Path,
  480. Win95UserName
  481. )
  482. ) {
  483. return GetLastError();
  484. }
  485. RegistryContext->Target = REG_TARGET_WIN95_REGISTRY;
  486. }
  487. else {
  488. NTSTATUS Status;
  489. UNICODE_STRING CurrentUserKeyPath;
  490. RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
  491. RegistryContext->UsersRoot = HKEY_USERS;
  492. RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
  493. wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
  494. wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
  495. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  496. if (!NT_SUCCESS( Status )) {
  497. SetLastError( RtlNtStatusToDosError( Status ) );
  498. return FALSE;
  499. }
  500. wcscpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer );
  501. RtlFreeUnicodeString( &CurrentUserKeyPath );
  502. RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY;
  503. }
  504. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  505. *DefaultRootKeyName = L"\\Registry";
  506. }
  507. RegistryContext->MachinePathLength = wcslen( RegistryContext->MachinePath );
  508. RegistryContext->UsersPathLength = wcslen( RegistryContext->UsersPath );
  509. RegistryContext->CurrentUserPathLength = wcslen( RegistryContext->CurrentUserPath );
  510. return NO_ERROR;
  511. }
  512. LONG
  513. RTDisconnectFromRegistry(
  514. IN PREG_CONTEXT RegistryContext
  515. )
  516. {
  517. switch( RegistryContext->Target ) {
  518. case REG_TARGET_DISCONNECTED:
  519. break;
  520. case REG_TARGET_LOCAL_REGISTRY:
  521. break;
  522. case REG_TARGET_REMOTE_REGISTRY:
  523. break;
  524. case REG_TARGET_WIN95_REGISTRY:
  525. // (_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 );
  526. // (_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 );
  527. (_Win95RegCloseKey)( RegistryContext->CurrentUserRoot );
  528. FreeLibrary( hVMMREG32 );
  529. break;
  530. case REG_TARGET_HIVE_REGISTRY:
  531. RegUnloadHive( RegistryContext );
  532. break;
  533. }
  534. if (PrivilegeEnabled) {
  535. RTDisableBackupRestorePrivilege();
  536. }
  537. RegistryContext->Target = REG_TARGET_DISCONNECTED;
  538. return NO_ERROR;
  539. }
  540. UNICODE_STRING RegHiveRootName;
  541. LONG
  542. RegLoadHive(
  543. IN PREG_CONTEXT RegistryContext,
  544. IN PWSTR HiveFileName,
  545. IN PWSTR HiveRootName
  546. )
  547. {
  548. NTSTATUS Status;
  549. UNICODE_STRING NtFileName;
  550. OBJECT_ATTRIBUTES File;
  551. SECURITY_DESCRIPTOR SecurityDescriptor;
  552. //
  553. // Create security descriptor with a NULL Dacl. This is necessary
  554. // because the security descriptor we pass in gets used in system
  555. // context. So if we just pass in NULL, then the Wrong Thing happens.
  556. // (but only on NTFS!)
  557. //
  558. Status = RtlCreateSecurityDescriptor( &SecurityDescriptor,
  559. SECURITY_DESCRIPTOR_REVISION
  560. );
  561. if (!NT_SUCCESS( Status )) {
  562. return RtlNtStatusToDosError( Status );
  563. }
  564. Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor,
  565. TRUE, // Dacl present
  566. NULL, // but grants all access
  567. FALSE
  568. );
  569. if (!NT_SUCCESS( Status )) {
  570. return RtlNtStatusToDosError( Status );
  571. }
  572. if (!RtlDosPathNameToNtPathName_U( HiveFileName,
  573. &NtFileName,
  574. NULL,
  575. NULL
  576. )
  577. ) {
  578. return ERROR_BAD_PATHNAME;
  579. }
  580. InitializeObjectAttributes( &File,
  581. &NtFileName,
  582. OBJ_CASE_INSENSITIVE,
  583. NULL,
  584. &SecurityDescriptor
  585. );
  586. RtlInitUnicodeString( &RegHiveRootName, L"\\Registry");
  587. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  588. &RegHiveRootName,
  589. OBJ_CASE_INSENSITIVE,
  590. NULL,
  591. NULL
  592. );
  593. Status = NtOpenKey( &RegistryContext->HiveRootHandle,
  594. MAXIMUM_ALLOWED,
  595. &RegistryContext->HiveRootKey
  596. );
  597. if (!NT_SUCCESS(Status)) {
  598. return RtlNtStatusToDosError( Status );
  599. }
  600. RtlInitUnicodeString( &RegHiveRootName, HiveRootName );
  601. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  602. &RegHiveRootName,
  603. OBJ_CASE_INSENSITIVE,
  604. RegistryContext->HiveRootHandle,
  605. NULL
  606. );
  607. NtUnloadKey( &RegistryContext->HiveRootKey );
  608. Status = NtLoadKey( &RegistryContext->HiveRootKey, &File );
  609. if (!NT_SUCCESS( Status )) {
  610. return RtlNtStatusToDosError( Status );
  611. }
  612. return NO_ERROR;
  613. }
  614. void
  615. RegUnloadHive(
  616. IN PREG_CONTEXT RegistryContext
  617. )
  618. {
  619. NTSTATUS Status;
  620. HANDLE Handle;
  621. PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
  622. Status = NtOpenKey( &Handle,
  623. MAXIMUM_ALLOWED,
  624. &RegistryContext->HiveRootKey
  625. );
  626. if (NT_SUCCESS( Status )) {
  627. NtFlushKey( Handle );
  628. NtClose( Handle );
  629. }
  630. p = RegistryContext->OpenHiveKeys;
  631. while (p) {
  632. RegCloseKey( p->KeyHandle );
  633. p1 = p;
  634. p = p->Next;
  635. HeapFree( GetProcessHeap(), 0, p1 );
  636. };
  637. do {
  638. Status = NtUnloadKey( &RegistryContext->HiveRootKey );
  639. }
  640. while (NT_SUCCESS( Status ) );
  641. NtClose( RegistryContext->HiveRootHandle );
  642. return;
  643. }
  644. void
  645. RegRememberOpenKey(
  646. IN PREG_CONTEXT RegistryContext,
  647. IN HKEY KeyHandle
  648. )
  649. {
  650. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  651. pp = &RegistryContext->OpenHiveKeys;
  652. while ((p = *pp) != NULL) {
  653. if (p->KeyHandle == KeyHandle) {
  654. p->ReferenceCount += 1;
  655. return;
  656. }
  657. else {
  658. pp = &p->Next;
  659. }
  660. }
  661. p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) );
  662. if (p != NULL) {
  663. p->KeyHandle = KeyHandle;
  664. p->ReferenceCount = 1;
  665. p->Next = NULL;
  666. *pp = p;
  667. }
  668. return;
  669. }
  670. void
  671. RegForgetOpenKey(
  672. IN PREG_CONTEXT RegistryContext,
  673. IN HKEY KeyHandle
  674. )
  675. {
  676. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  677. pp = &RegistryContext->OpenHiveKeys;
  678. while ((p = *pp) != NULL) {
  679. if (p->KeyHandle == KeyHandle) {
  680. p->ReferenceCount -= 1;
  681. if (p->ReferenceCount == 0) {
  682. *pp = p->Next;
  683. HeapFree( GetProcessHeap(), 0, p );
  684. return;
  685. }
  686. }
  687. else {
  688. pp = &p->Next;
  689. }
  690. }
  691. return;
  692. }
  693. BOOLEAN
  694. RegCheckPrefix(
  695. IN OUT PCWSTR *s,
  696. IN PCWSTR Prefix,
  697. IN ULONG PrefixLength
  698. )
  699. {
  700. if (PrefixLength == 0) {
  701. return FALSE;
  702. }
  703. if (!_wcsnicmp( *s, Prefix, PrefixLength )) {
  704. *s += PrefixLength;
  705. return TRUE;
  706. }
  707. return FALSE;
  708. }
  709. BOOLEAN
  710. RegValidateKeyPath(
  711. IN PREG_CONTEXT RegistryContext,
  712. IN OUT PHKEY RootKeyHandle,
  713. IN OUT PCWSTR *SubKeyName
  714. )
  715. {
  716. PCWSTR s;
  717. s = *SubKeyName;
  718. if (*RootKeyHandle == NULL) {
  719. if (RegCheckPrefix( &s, L"USER:", 5 ) ||
  720. RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 )
  721. ) {
  722. if (RegistryContext->CurrentUserRoot == NULL) {
  723. SetLastError( ERROR_BAD_PATHNAME );
  724. return FALSE;
  725. }
  726. if (*s == L'\\') {
  727. s += 1;
  728. }
  729. else
  730. if (s[-1] != L':' && *s != UNICODE_NULL) {
  731. SetLastError( ERROR_BAD_PATHNAME );
  732. return FALSE;
  733. }
  734. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  735. }
  736. else
  737. if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) {
  738. if (*s == L'\\') {
  739. s += 1;
  740. }
  741. else
  742. if (*s != UNICODE_NULL) {
  743. SetLastError( ERROR_BAD_PATHNAME );
  744. return FALSE;
  745. }
  746. *RootKeyHandle = RegistryContext->MachineRoot;
  747. }
  748. else
  749. if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) {
  750. if (*s == L'\\') {
  751. s += 1;
  752. }
  753. else
  754. if (*s != UNICODE_NULL) {
  755. SetLastError( ERROR_BAD_PATHNAME );
  756. return FALSE;
  757. }
  758. *RootKeyHandle = RegistryContext->UsersRoot;
  759. }
  760. else
  761. if (*s != L'\\') {
  762. SetLastError( ERROR_BAD_PATHNAME );
  763. return FALSE;
  764. }
  765. else
  766. if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) {
  767. *RootKeyHandle = RegistryContext->MachineRoot;
  768. if (*s == L'\\') {
  769. s += 1;
  770. }
  771. }
  772. else
  773. if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) {
  774. *RootKeyHandle = RegistryContext->UsersRoot;
  775. if (*s == L'\\') {
  776. s += 1;
  777. }
  778. }
  779. else
  780. if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) {
  781. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  782. if (*s == L'\\') {
  783. s += 1;
  784. }
  785. }
  786. else
  787. if (!_wcsicmp( *SubKeyName, L"\\Registry" )) {
  788. *RootKeyHandle = NULL;
  789. }
  790. else {
  791. SetLastError( ERROR_BAD_PATHNAME );
  792. return FALSE;
  793. }
  794. }
  795. else
  796. if (*s == L'\\') {
  797. SetLastError( ERROR_BAD_PATHNAME );
  798. return FALSE;
  799. }
  800. *SubKeyName = s;
  801. return TRUE;
  802. }
  803. LONG
  804. RTCreateKey(
  805. IN PREG_CONTEXT RegistryContext,
  806. IN HKEY RootKeyHandle,
  807. IN PCWSTR SubKeyName,
  808. IN ACCESS_MASK DesiredAccess,
  809. IN ULONG CreateOptions,
  810. IN PVOID SecurityDescriptor,
  811. OUT PHKEY ReturnedKeyHandle,
  812. OUT PULONG Disposition
  813. )
  814. {
  815. LONG Error;
  816. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  817. return GetLastError();
  818. }
  819. if (RootKeyHandle == NULL) {
  820. *Disposition = REG_OPENED_EXISTING_KEY;
  821. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  822. return NO_ERROR;
  823. }
  824. else
  825. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  826. *ReturnedKeyHandle = NULL;
  827. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  828. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  829. }
  830. else
  831. if (!_wcsicmp( SubKeyName, L"Users" )) {
  832. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  833. }
  834. if (*ReturnedKeyHandle != NULL) {
  835. return NO_ERROR;
  836. }
  837. else {
  838. return ERROR_PATH_NOT_FOUND;
  839. }
  840. }
  841. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  842. UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
  843. if (SubKeyName != NULL) {
  844. if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
  845. return GetLastError();
  846. }
  847. p = AnsiSubKeyName;
  848. }
  849. else {
  850. p = NULL;
  851. }
  852. Error = (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle );
  853. if (Error == NO_ERROR) {
  854. *Disposition = REG_OPENED_EXISTING_KEY;
  855. }
  856. else {
  857. Error = (_Win95RegCreateKey)( RootKeyHandle, p, ReturnedKeyHandle );
  858. if (Error == NO_ERROR) {
  859. *Disposition = REG_CREATED_NEW_KEY;
  860. }
  861. }
  862. }
  863. else {
  864. SECURITY_ATTRIBUTES SecurityAttributes;
  865. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  866. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  867. SecurityAttributes.bInheritHandle = FALSE;
  868. Error = RegCreateKeyEx( RootKeyHandle,
  869. SubKeyName,
  870. 0,
  871. NULL,
  872. CreateOptions,
  873. (REGSAM)DesiredAccess,
  874. &SecurityAttributes,
  875. ReturnedKeyHandle,
  876. Disposition
  877. );
  878. if (Error == NO_ERROR &&
  879. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  880. ) {
  881. RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
  882. }
  883. if (Error == NO_ERROR &&
  884. *Disposition == REG_OPENED_EXISTING_KEY &&
  885. SecurityDescriptor != NULL
  886. ) {
  887. RegSetKeySecurity( *ReturnedKeyHandle,
  888. DACL_SECURITY_INFORMATION,
  889. SecurityDescriptor
  890. );
  891. }
  892. }
  893. return Error;
  894. }
  895. LONG
  896. RTOpenKey(
  897. IN PREG_CONTEXT RegistryContext,
  898. IN HKEY RootKeyHandle,
  899. IN PCWSTR SubKeyName,
  900. IN ACCESS_MASK DesiredAccess,
  901. IN ULONG OpenOptions,
  902. OUT PHKEY ReturnedKeyHandle
  903. )
  904. {
  905. LONG Error;
  906. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  907. return GetLastError();
  908. }
  909. if (RootKeyHandle == NULL) {
  910. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  911. return NO_ERROR;
  912. }
  913. else
  914. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  915. *ReturnedKeyHandle = NULL;
  916. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  917. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  918. }
  919. else
  920. if (!_wcsicmp( SubKeyName, L"Users" )) {
  921. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  922. }
  923. if (*ReturnedKeyHandle != NULL) {
  924. return NO_ERROR;
  925. }
  926. else {
  927. return ERROR_PATH_NOT_FOUND;
  928. }
  929. }
  930. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  931. UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
  932. if (SubKeyName != NULL) {
  933. if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
  934. return GetLastError();
  935. }
  936. p = AnsiSubKeyName;
  937. }
  938. else {
  939. p = NULL;
  940. }
  941. return (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle );
  942. }
  943. else {
  944. Error = RegOpenKeyEx( RootKeyHandle,
  945. SubKeyName,
  946. OpenOptions,
  947. DesiredAccess,
  948. ReturnedKeyHandle
  949. );
  950. if (Error == NO_ERROR &&
  951. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  952. ) {
  953. RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
  954. }
  955. return Error;
  956. }
  957. }
  958. LONG
  959. RTCloseKey(
  960. IN PREG_CONTEXT RegistryContext,
  961. IN HKEY KeyHandle
  962. )
  963. {
  964. LONG Error;
  965. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  966. return NO_ERROR;
  967. }
  968. else
  969. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  970. return (_Win95RegCloseKey)( KeyHandle );
  971. }
  972. else {
  973. Error = RegCloseKey( KeyHandle );
  974. if (Error == NO_ERROR &&
  975. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  976. ) {
  977. RegForgetOpenKey( RegistryContext, KeyHandle );
  978. }
  979. return Error;
  980. }
  981. }
  982. LONG
  983. RTFlushKey(
  984. IN PREG_CONTEXT RegistryContext,
  985. IN HKEY KeyHandle
  986. )
  987. {
  988. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  989. return NO_ERROR;
  990. }
  991. else
  992. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  993. return (_Win95RegFlushKey)( KeyHandle );
  994. }
  995. else {
  996. return RegFlushKey( KeyHandle );
  997. }
  998. }
  999. LONG
  1000. RTEnumerateKey(
  1001. IN PREG_CONTEXT RegistryContext,
  1002. IN HKEY KeyHandle,
  1003. IN ULONG Index,
  1004. OUT PFILETIME LastWriteTime,
  1005. IN OUT PULONG KeyNameLength,
  1006. OUT PWSTR KeyName
  1007. )
  1008. {
  1009. ULONG Error;
  1010. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  1011. if (Index == 0) {
  1012. if (*KeyNameLength <= 7) {
  1013. return ERROR_MORE_DATA;
  1014. }
  1015. else {
  1016. wcscpy( KeyName, L"Machine" );
  1017. return NO_ERROR;
  1018. }
  1019. }
  1020. else
  1021. if (Index == 1) {
  1022. if (*KeyNameLength <= 5) {
  1023. return ERROR_MORE_DATA;
  1024. }
  1025. else {
  1026. wcscpy( KeyName, L"Users" );
  1027. return NO_ERROR;
  1028. }
  1029. }
  1030. else {
  1031. return ERROR_NO_MORE_ITEMS;
  1032. }
  1033. }
  1034. else
  1035. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1036. UCHAR AnsiKeyName[ MAX_PATH ];
  1037. ULONG AnsiKeyNameLength;
  1038. AnsiKeyNameLength = sizeof( AnsiKeyName );
  1039. Error = _Win95RegEnumKey( KeyHandle,
  1040. Index,
  1041. AnsiKeyName,
  1042. AnsiKeyNameLength
  1043. );
  1044. if (Error == NO_ERROR) {
  1045. if (strlen( AnsiKeyName ) >= *KeyNameLength) {
  1046. return ERROR_MORE_DATA;
  1047. }
  1048. *KeyNameLength = RegAnsiToUnicode( AnsiKeyName, KeyName, AnsiKeyNameLength );
  1049. if (*KeyNameLength == 0) {
  1050. return GetLastError();
  1051. }
  1052. RtlZeroMemory( LastWriteTime, sizeof( *LastWriteTime ) );
  1053. }
  1054. }
  1055. else {
  1056. Error = RegEnumKeyEx( KeyHandle,
  1057. Index,
  1058. KeyName,
  1059. KeyNameLength,
  1060. NULL,
  1061. NULL,
  1062. NULL,
  1063. LastWriteTime
  1064. );
  1065. }
  1066. return Error;
  1067. }
  1068. LONG
  1069. RTEnumerateValueKey(
  1070. IN PREG_CONTEXT RegistryContext,
  1071. IN HKEY KeyHandle,
  1072. IN ULONG Index,
  1073. OUT PULONG ValueType,
  1074. IN OUT PULONG ValueNameLength,
  1075. OUT PWSTR ValueName,
  1076. IN OUT PULONG ValueDataLength,
  1077. OUT PVOID ValueData
  1078. )
  1079. {
  1080. ULONG Error;
  1081. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  1082. return ERROR_NO_MORE_ITEMS;
  1083. }
  1084. else
  1085. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1086. UCHAR AnsiValueName[ MAX_PATH ];
  1087. ULONG AnsiValueNameLength;
  1088. LPSTR AnsiValueData;
  1089. ULONG OriginalValueDataLength;
  1090. AnsiValueNameLength = sizeof( AnsiValueName );
  1091. OriginalValueDataLength = *ValueDataLength;
  1092. Error = (_Win95RegEnumValue)( KeyHandle,
  1093. Index,
  1094. AnsiValueName,
  1095. &AnsiValueNameLength,
  1096. 0,
  1097. ValueType,
  1098. ValueData,
  1099. ValueDataLength
  1100. );
  1101. if (Error != NO_ERROR) {
  1102. return Error;
  1103. }
  1104. if (AnsiValueNameLength >= *ValueNameLength) {
  1105. return ERROR_MORE_DATA;
  1106. }
  1107. if (RegAnsiToUnicode( AnsiValueName, ValueName, AnsiValueNameLength ) == 0) {
  1108. return GetLastError();
  1109. }
  1110. if (*ValueType == REG_SZ) {
  1111. AnsiValueData = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength );
  1112. if (AnsiValueData == NULL) {
  1113. return ERROR_OUTOFMEMORY;
  1114. }
  1115. RtlMoveMemory( AnsiValueData, ValueData, *ValueDataLength );
  1116. if (RegAnsiToUnicode( AnsiValueData, (PWSTR)ValueData, *ValueDataLength ) == 0) {
  1117. Error = GetLastError();
  1118. }
  1119. else {
  1120. *ValueDataLength *= sizeof( WCHAR );
  1121. }
  1122. HeapFree( GetProcessHeap(), 0, AnsiValueData );
  1123. }
  1124. return Error;
  1125. }
  1126. else {
  1127. Error = RegEnumValue( KeyHandle,
  1128. Index,
  1129. ValueName,
  1130. ValueNameLength,
  1131. NULL,
  1132. ValueType,
  1133. ValueData,
  1134. ValueDataLength
  1135. );
  1136. if (Error == NO_ERROR) {
  1137. RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
  1138. }
  1139. return Error;
  1140. }
  1141. }
  1142. LONG
  1143. RTQueryKey(
  1144. IN PREG_CONTEXT RegistryContext,
  1145. IN HKEY KeyHandle,
  1146. OUT PFILETIME LastWriteTime,
  1147. OUT PULONG NumberOfSubkeys,
  1148. OUT PULONG NumberOfValues
  1149. )
  1150. {
  1151. LONG Error;
  1152. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  1153. if (NumberOfSubkeys != NULL) {
  1154. *NumberOfSubkeys = 2;
  1155. }
  1156. if (NumberOfValues != NULL) {
  1157. *NumberOfValues = 0;
  1158. }
  1159. return NO_ERROR;
  1160. }
  1161. else
  1162. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1163. Error = (_Win95RegQueryInfoKey)( KeyHandle,
  1164. NULL,
  1165. NULL,
  1166. NULL,
  1167. NumberOfSubkeys,
  1168. NULL,
  1169. NULL,
  1170. NumberOfValues,
  1171. NULL,
  1172. NULL,
  1173. NULL,
  1174. (PVOID)LastWriteTime
  1175. );
  1176. }
  1177. else {
  1178. Error = RegQueryInfoKey( KeyHandle, // hKey,
  1179. NULL, // lpClass,
  1180. NULL, // lpcbClass,
  1181. NULL, // lpReserved,
  1182. NumberOfSubkeys, // lpcSubKeys,
  1183. NULL, // lpcbMaxSubKeyLen,
  1184. NULL, // lpcbMaxClassLen,
  1185. NumberOfValues, // lpcValues,
  1186. NULL, // lpcbMaxValueNameLen,
  1187. NULL, // lpcbMaxValueLen,
  1188. NULL, // lpcbSecurityDescriptor,
  1189. LastWriteTime // lpftLastWriteTime
  1190. );
  1191. }
  1192. return Error;
  1193. }
  1194. LONG
  1195. RTQueryValueKey(
  1196. IN PREG_CONTEXT RegistryContext,
  1197. IN HKEY KeyHandle,
  1198. IN PWSTR ValueName,
  1199. OUT PULONG ValueType,
  1200. IN OUT PULONG ValueDataLength,
  1201. OUT PVOID ValueData
  1202. )
  1203. {
  1204. LONG Error;
  1205. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1206. UCHAR AnsiValueName[ MAX_PATH ], *p;
  1207. ULONG OriginalValueDataLength;
  1208. if (ValueName != NULL) {
  1209. if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
  1210. return GetLastError();
  1211. }
  1212. p = AnsiValueName;
  1213. }
  1214. else {
  1215. p = NULL;
  1216. }
  1217. OriginalValueDataLength = *ValueDataLength;
  1218. Error = (_Win95RegQueryValueEx)( KeyHandle,
  1219. p,
  1220. NULL,
  1221. ValueType,
  1222. ValueData,
  1223. ValueDataLength
  1224. );
  1225. if (Error == NO_ERROR && *ValueType == REG_SZ) {
  1226. if ((*ValueDataLength * sizeof( WCHAR )) > OriginalValueDataLength) {
  1227. return ERROR_MORE_DATA;
  1228. }
  1229. p = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength );
  1230. if (p == NULL) {
  1231. return ERROR_OUTOFMEMORY;
  1232. }
  1233. RtlMoveMemory( p, ValueData, *ValueDataLength );
  1234. if (RegAnsiToUnicode( (LPCSTR)p, (PWSTR)ValueData, *ValueDataLength ) == 0) {
  1235. Error = GetLastError();
  1236. }
  1237. else {
  1238. *ValueDataLength *= sizeof( WCHAR );
  1239. *ValueDataLength += sizeof( UNICODE_NULL );
  1240. }
  1241. HeapFree( GetProcessHeap(), 0, p );
  1242. }
  1243. }
  1244. else {
  1245. Error = RegQueryValueEx( KeyHandle,
  1246. ValueName,
  1247. NULL,
  1248. ValueType,
  1249. ValueData,
  1250. ValueDataLength
  1251. );
  1252. if (Error == NO_ERROR) {
  1253. RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
  1254. }
  1255. }
  1256. return Error;
  1257. }
  1258. LONG
  1259. RTSetValueKey(
  1260. IN PREG_CONTEXT RegistryContext,
  1261. IN HKEY KeyHandle,
  1262. IN PWSTR ValueName,
  1263. IN ULONG ValueType,
  1264. IN ULONG ValueDataLength,
  1265. IN PVOID ValueData
  1266. )
  1267. {
  1268. LONG Error;
  1269. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1270. UCHAR AnsiValueName[ MAX_PATH ], *p;
  1271. ULONG OriginalValueDataLength;
  1272. LPSTR AnsiValueData;
  1273. if (ValueName != NULL) {
  1274. if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
  1275. return GetLastError();
  1276. }
  1277. p = AnsiValueName;
  1278. }
  1279. else {
  1280. p = NULL;
  1281. }
  1282. if (ValueType == REG_SZ) {
  1283. AnsiValueData = HeapAlloc( GetProcessHeap(), 0, ValueDataLength * 2 );
  1284. if (AnsiValueData == NULL) {
  1285. return ERROR_OUTOFMEMORY;
  1286. }
  1287. ValueDataLength = RegUnicodeToAnsi( ValueData, AnsiValueData, ValueDataLength );
  1288. if (ValueDataLength == 0) {
  1289. return GetLastError();
  1290. }
  1291. ValueData = AnsiValueData;
  1292. }
  1293. else {
  1294. AnsiValueData = NULL;
  1295. }
  1296. Error = (_Win95RegSetValueEx)( KeyHandle,
  1297. p,
  1298. 0,
  1299. ValueType,
  1300. ValueData,
  1301. ValueDataLength
  1302. );
  1303. if (AnsiValueData != NULL) {
  1304. HeapFree( GetProcessHeap(), 0, AnsiValueData );
  1305. }
  1306. if (p != NULL) {
  1307. HeapFree( GetProcessHeap(), 0, p );
  1308. }
  1309. }
  1310. else {
  1311. Error = RegSetValueEx( KeyHandle,
  1312. ValueName,
  1313. 0,
  1314. ValueType,
  1315. ValueData,
  1316. ValueDataLength
  1317. );
  1318. }
  1319. return Error;
  1320. }
  1321. LONG
  1322. RTDeleteKey(
  1323. IN PREG_CONTEXT RegistryContext,
  1324. IN HKEY KeyHandle,
  1325. IN PCWSTR SubKeyName
  1326. )
  1327. {
  1328. if (!RegValidateKeyPath( RegistryContext, &KeyHandle, &SubKeyName )) {
  1329. return GetLastError();
  1330. }
  1331. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1332. UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
  1333. if (SubKeyName != NULL) {
  1334. if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) {
  1335. return GetLastError();
  1336. }
  1337. p = AnsiSubKeyName;
  1338. }
  1339. else {
  1340. p = NULL;
  1341. }
  1342. return (_Win95RegDeleteKey)( KeyHandle, p );
  1343. }
  1344. else {
  1345. return RegDeleteKey( KeyHandle, SubKeyName );
  1346. }
  1347. }
  1348. LONG
  1349. RTDeleteValueKey(
  1350. IN PREG_CONTEXT RegistryContext,
  1351. IN HKEY KeyHandle,
  1352. IN PWSTR ValueName
  1353. )
  1354. {
  1355. if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) {
  1356. UCHAR AnsiValueName[ MAX_PATH ], *p;
  1357. ULONG OriginalValueDataLength;
  1358. LPSTR AnsiValueData;
  1359. if (ValueName != NULL) {
  1360. if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) {
  1361. return GetLastError();
  1362. }
  1363. p = AnsiValueName;
  1364. }
  1365. else {
  1366. p = NULL;
  1367. }
  1368. return (_Win95RegDeleteValue)( KeyHandle,
  1369. p
  1370. );
  1371. }
  1372. else {
  1373. return RegDeleteValue( KeyHandle, ValueName );
  1374. }
  1375. }
  1376. LONG
  1377. RTLoadAsciiFileAsUnicode(
  1378. IN PWSTR FileName,
  1379. OUT PREG_UNICODE_FILE UnicodeFile
  1380. )
  1381. {
  1382. LONG Error = NO_ERROR;
  1383. HANDLE File;
  1384. DWORD FileSize;
  1385. DWORD CharsInFile;
  1386. DWORD BytesRead;
  1387. DWORD BufferSize, i, i1, LineCount, DeferredLineCount;
  1388. PVOID BufferBase;
  1389. PWSTR Src, Src1, Dst;
  1390. File = CreateFile( FileName,
  1391. FILE_GENERIC_READ,
  1392. FILE_SHARE_DELETE |
  1393. FILE_SHARE_READ |
  1394. FILE_SHARE_WRITE,
  1395. NULL,
  1396. OPEN_EXISTING,
  1397. 0,
  1398. NULL
  1399. );
  1400. if (File == INVALID_HANDLE_VALUE) {
  1401. return GetLastError();
  1402. }
  1403. FileSize = GetFileSize( File, NULL );
  1404. if (FileSize == INVALID_FILE_SIZE) {
  1405. CloseHandle( File );
  1406. return GetLastError();
  1407. }
  1408. BufferSize = FileSize * sizeof( WCHAR );
  1409. BufferSize += sizeof( UNICODE_NULL );
  1410. BufferBase = NULL;
  1411. BufferBase = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE );
  1412. if (BufferBase != NULL) {
  1413. if (ReadFile( File, BufferBase, FileSize, &BytesRead, NULL )) {
  1414. if (BytesRead != FileSize) {
  1415. Error = ERROR_HANDLE_EOF;
  1416. }
  1417. else
  1418. if (!GetFileTime( File, NULL, NULL, &UnicodeFile->LastWriteTime )) {
  1419. Error = GetLastError();
  1420. }
  1421. else {
  1422. Error = NO_ERROR;
  1423. }
  1424. }
  1425. if (Error != NO_ERROR) {
  1426. VirtualFree( BufferBase, 0, MEM_RELEASE );
  1427. }
  1428. } else {
  1429. Error = GetLastError();
  1430. }
  1431. CloseHandle( File );
  1432. if (Error != NO_ERROR) {
  1433. return Error;
  1434. }
  1435. Src = (PWSTR)BufferBase;
  1436. if (!IsTextUnicode( BufferBase, FileSize, NULL )) {
  1437. RtlMoveMemory( (PCHAR)BufferBase + FileSize, BufferBase, FileSize );
  1438. CharsInFile = RegAnsiToUnicode( (PCHAR)BufferBase + FileSize, BufferBase, FileSize );
  1439. if (CharsInFile == 0) {
  1440. return GetLastError();
  1441. }
  1442. }
  1443. else {
  1444. CharsInFile = FileSize / sizeof( WCHAR );
  1445. //
  1446. // Skip ByteOrderMark
  1447. //
  1448. if (Src[0] == 0xfeff || Src[0] == 0xfffe) {
  1449. Src++;
  1450. CharsInFile--;
  1451. }
  1452. }
  1453. DeferredLineCount = 0;
  1454. Dst = (PWSTR)BufferBase;
  1455. i = 0;
  1456. //
  1457. // Now loop over the in memory copy of the file, collapsing all carriage
  1458. // return line feed pairs into just new lines, and removing all line
  1459. // continuation characters and the spaces that surround them. This lets
  1460. // RTParseNextLine see a single line for each Key Name or Value input,
  1461. // terminated by a new line character.
  1462. //
  1463. while (i < CharsInFile) {
  1464. //
  1465. // See if we just went over a line continuation character
  1466. //
  1467. if (i > 0 && Src[-1] == L'\\' && (*Src == L'\r' || *Src == L'\n')) {
  1468. //
  1469. // Move back over the line continuation we just copied the previous iteration
  1470. //
  1471. if (Dst[-1] == L'\\') {
  1472. --Dst;
  1473. }
  1474. //
  1475. // Move back over all but one of any space characters that preceed
  1476. // the line continuation character. The may be none, in which case
  1477. // we leave it be, as the user must want no space
  1478. //
  1479. while (Dst > (PWSTR)BufferBase) {
  1480. if (Dst[-1] > L' ') {
  1481. break;
  1482. }
  1483. Dst -= 1;
  1484. }
  1485. //
  1486. // Leave one space, if there is one
  1487. //
  1488. if (Dst[0] == L' ') {
  1489. Dst += 1;
  1490. }
  1491. //
  1492. // Now, skip over the new line after the line continuation. We
  1493. // actually will skip over any number of them, keeping count so
  1494. // we can update the source file line number correctly.
  1495. //
  1496. LineCount = 0;
  1497. while (i < CharsInFile) {
  1498. if (*Src == L'\n') {
  1499. i++;
  1500. Src++;
  1501. LineCount++;
  1502. }
  1503. else
  1504. if (*Src == L'\r' &&
  1505. (i+1) < CharsInFile &&
  1506. Src[ 1 ] == L'\n'
  1507. ) {
  1508. i += 2;
  1509. Src += 2;
  1510. LineCount++;
  1511. }
  1512. else {
  1513. break;
  1514. }
  1515. }
  1516. //
  1517. // If we saw more than just new line after the line continuation
  1518. // character, then put them back into the destination as just
  1519. // new lines, without any carriage returns.
  1520. //
  1521. if (LineCount > 1) {
  1522. DeferredLineCount += LineCount;
  1523. while (DeferredLineCount) {
  1524. DeferredLineCount -= 1;
  1525. *Dst++ = L'\n';
  1526. }
  1527. }
  1528. else {
  1529. DeferredLineCount += 1;
  1530. //
  1531. // Skip leading spaces of next line of continuation
  1532. while (i < CharsInFile && (*Src == L' ' || *Src == L'\t')) {
  1533. i++;
  1534. Src++;
  1535. }
  1536. }
  1537. //
  1538. // All done if we hit the end of the file
  1539. //
  1540. if (i >= CharsInFile) {
  1541. break;
  1542. }
  1543. }
  1544. else
  1545. if ((*Src == '\r' && Src[1] == '\n') || *Src == '\n') {
  1546. while (TRUE) {
  1547. while (i < CharsInFile && (*Src == '\r' || *Src == '\n')) {
  1548. i++;
  1549. Src++;
  1550. }
  1551. Src1 = Src;
  1552. i1 = i;
  1553. while (i1 < CharsInFile && (*Src1 == ' ' || *Src1 == '\t')) {
  1554. i1++;
  1555. Src1++;
  1556. }
  1557. if (i1 < CharsInFile &&
  1558. (*Src1 == '\r' && Src1[1] == '\n') || *Src1 == '\n'
  1559. ) {
  1560. Src = Src1;
  1561. i = i1;
  1562. }
  1563. else {
  1564. break;
  1565. }
  1566. }
  1567. while (DeferredLineCount) {
  1568. DeferredLineCount -= 1;
  1569. *Dst++ = L'\n';
  1570. }
  1571. *Dst++ = L'\n';
  1572. }
  1573. else {
  1574. i++;
  1575. *Dst++ = *Src++;
  1576. }
  1577. }
  1578. //
  1579. // Make sure line ends with a CRLF sequence.
  1580. //
  1581. while (DeferredLineCount) {
  1582. DeferredLineCount -= 1;
  1583. *Dst++ = L'\n';
  1584. }
  1585. *Dst++ = L'\n';
  1586. *Dst = UNICODE_NULL;
  1587. UnicodeFile->FileName = FileName;
  1588. UnicodeFile->FileContents = BufferBase;
  1589. UnicodeFile->EndOfFile = Dst;
  1590. UnicodeFile->NextLine = BufferBase;
  1591. UnicodeFile->NextLineNumber = 1;
  1592. return NO_ERROR;
  1593. }
  1594. void
  1595. RTUnloadUnicodeFile(
  1596. IN OUT PREG_UNICODE_FILE UnicodeFile
  1597. )
  1598. {
  1599. VirtualFree( UnicodeFile->FileContents, 0, MEM_RELEASE );
  1600. return;
  1601. }
  1602. #define ACL_LIST_START L'['
  1603. #define ACL_LIST_END L']'
  1604. BOOLEAN
  1605. RegGetMultiString(
  1606. IN BOOLEAN BackwardsCompatibleInput,
  1607. IN OUT PWSTR *ValueString,
  1608. IN OUT PWSTR *ValueData,
  1609. IN ULONG MaximumValueLength,
  1610. IN OUT PULONG ValueLength
  1611. );
  1612. BOOLEAN
  1613. RegReadMultiSzFile(
  1614. IN OUT PREG_UNICODE_PARSE ParsedLine,
  1615. IN BOOLEAN BackwardsCompatibleInput,
  1616. IN PWSTR FileName,
  1617. IN OUT PVOID ValueData,
  1618. IN OUT PULONG ValueLength
  1619. );
  1620. BOOLEAN
  1621. RegReadBinaryFile(
  1622. IN OUT PREG_UNICODE_PARSE ParsedLine,
  1623. IN PWSTR FileName,
  1624. IN OUT PVOID ValueData,
  1625. IN OUT PULONG ValueLength
  1626. );
  1627. BOOLEAN
  1628. RTParseNextLine(
  1629. IN OUT PREG_UNICODE_FILE UnicodeFile,
  1630. OUT PREG_UNICODE_PARSE ParsedLine
  1631. )
  1632. {
  1633. PWSTR BeginLine, EqualSign, AclBracket, AclStart, s, s1;
  1634. WCHAR QuoteChar;
  1635. if (ParsedLine->IsKeyName && ParsedLine->SecurityDescriptor) {
  1636. RegDestroySecurity( ParsedLine->SecurityDescriptor );
  1637. }
  1638. RtlZeroMemory( ParsedLine, sizeof( *ParsedLine ) );
  1639. while (TRUE) {
  1640. if (!(s = UnicodeFile->NextLine)) {
  1641. ParsedLine->AtEndOfFile = TRUE;
  1642. return FALSE;
  1643. }
  1644. UnicodeFile->NextLine = NULL;
  1645. if (*s == UNICODE_NULL) {
  1646. ParsedLine->AtEndOfFile = TRUE;
  1647. return FALSE;
  1648. }
  1649. while (*s <= L' ') {
  1650. if (*s == L' ') {
  1651. ParsedLine->IndentAmount += 1;
  1652. }
  1653. else
  1654. if (*s == L'\t') {
  1655. ParsedLine->IndentAmount = ((ParsedLine->IndentAmount + 8) -
  1656. (ParsedLine->IndentAmount % 8)
  1657. );
  1658. }
  1659. if (++s >= UnicodeFile->EndOfFile) {
  1660. ParsedLine->AtEndOfFile = TRUE;
  1661. return FALSE;
  1662. }
  1663. }
  1664. BeginLine = s;
  1665. EqualSign = NULL;
  1666. AclBracket = NULL;
  1667. if (!UnicodeFile->BackwardsCompatibleInput && *s == L';') {
  1668. while (s < UnicodeFile->EndOfFile) {
  1669. if (*s == L'\n') {
  1670. do {
  1671. UnicodeFile->NextLineNumber += 1;
  1672. *s++ = UNICODE_NULL;
  1673. }
  1674. while (*s == L'\n');
  1675. break;
  1676. }
  1677. else {
  1678. s += 1;
  1679. }
  1680. }
  1681. BeginLine = s;
  1682. UnicodeFile->NextLine = s;
  1683. }
  1684. else
  1685. if (*s != '\n') {
  1686. //
  1687. // If not being backward compatible, see if the first thing on
  1688. // the line is the beginning of a quoted string.
  1689. //
  1690. if (!UnicodeFile->BackwardsCompatibleInput && (*s == L'"' || *s == L'\'')) {
  1691. //
  1692. // Yes, it is either a quoted key name or value name. Find the
  1693. // the trailing quote. Specifically do NOT support quotes inside
  1694. // a quoted string, other than a different kind. Which means unless
  1695. // you want both types of quoted characters within the same name
  1696. // you wont care.
  1697. //
  1698. QuoteChar = *s++;
  1699. BeginLine += 1;
  1700. while (s < UnicodeFile->EndOfFile && *s != QuoteChar) {
  1701. s += 1;
  1702. }
  1703. //
  1704. // If trailing quote not found, then return an error
  1705. //
  1706. if (*s != QuoteChar) {
  1707. ParsedLine->ParseFailureReason = ParseFailInvalidQuoteCharacter;
  1708. return FALSE;
  1709. }
  1710. //
  1711. // Mark the end of the name and move past the trailing quote
  1712. //
  1713. *s++ = UNICODE_NULL;
  1714. }
  1715. //
  1716. // Now scan forward looking for one of the following:
  1717. //
  1718. // equal sign - this would mean the stuff to the left
  1719. // of the equal sign is a value name and the stuff
  1720. // to the right is the value type and data.
  1721. //
  1722. // left square bracket - this would mean the stuff to the
  1723. // left of the square bracket is a key name and the
  1724. // stuff to the right is the security descriptor information
  1725. //
  1726. // end of line - this would mean the stuff to the left
  1727. // is a key name, with no security descriptor.
  1728. //
  1729. while (s < UnicodeFile->EndOfFile) {
  1730. if (*s == L'=') {
  1731. //
  1732. // We found an equal sign, so value name is to the left
  1733. // and value type and data follows.
  1734. //
  1735. EqualSign = s;
  1736. //
  1737. // Ignore any left square bracket we might have seen
  1738. // in before this. It must have been part of the value
  1739. // name.
  1740. AclBracket = NULL;
  1741. //
  1742. // All done scanning
  1743. //
  1744. break;
  1745. }
  1746. else
  1747. if (*s == ACL_LIST_START) {
  1748. //
  1749. // We found a left square bracket. Keep scanning
  1750. // in case there is an equal sign later.
  1751. //
  1752. AclBracket = s;
  1753. s += 1;
  1754. }
  1755. else
  1756. if (*s == L'\n') {
  1757. //
  1758. // We found end of line, so key name is to the left.
  1759. // Update where to start next time we are called.
  1760. //
  1761. UnicodeFile->NextLine = s + 1;
  1762. break;
  1763. }
  1764. else
  1765. if (*s == L'\t') {
  1766. //
  1767. // Convert imbedded hard tabs to single spaces
  1768. //
  1769. *s++ = L' ';
  1770. }
  1771. else {
  1772. //
  1773. // Nothing interesting, keep looking.
  1774. //
  1775. s += 1;
  1776. }
  1777. }
  1778. //
  1779. // Trim any trailing spaces off the end of what is to the
  1780. // left of where we are. The make sure we stop looking
  1781. // if we see the null character put down over the trailing
  1782. // quote character above, if any.
  1783. //
  1784. *s = UNICODE_NULL;
  1785. while (s > BeginLine && *--s <= L' ' && *s) {
  1786. *s = UNICODE_NULL;
  1787. }
  1788. //
  1789. // BeginLine now points to either the null terminated value
  1790. // name or key name. EqualSign, if non-null, points to the
  1791. // equal sign, so scan forward and find the terminating new line,
  1792. // and store a null there to terminate the input. Otherwise,
  1793. // we already stored a null over the terminating new line above.
  1794. //
  1795. if (EqualSign != NULL) {
  1796. s = EqualSign + 1;
  1797. while (s < UnicodeFile->EndOfFile) {
  1798. if (*s == '\n') {
  1799. *s = UNICODE_NULL;
  1800. break;
  1801. }
  1802. s += 1;
  1803. }
  1804. //
  1805. // Update where we should start next time we are called.
  1806. //
  1807. UnicodeFile->NextLine = s + 1;
  1808. }
  1809. else
  1810. if (AclBracket != NULL) {
  1811. //
  1812. // Since we did not stop on the AclBracket, go back an
  1813. // clobber it and any spaces before it.
  1814. //
  1815. s = AclBracket;
  1816. *s = UNICODE_NULL;
  1817. while (s > BeginLine && *--s <= L' ' && *s) {
  1818. *s = UNICODE_NULL;
  1819. }
  1820. }
  1821. //
  1822. // Tell them which line number and where the line begins
  1823. //
  1824. ParsedLine->LineNumber = UnicodeFile->NextLineNumber;
  1825. UnicodeFile->NextLineNumber += 1;
  1826. ParsedLine->BeginLine = BeginLine;
  1827. //
  1828. // Now handle value or key semantics
  1829. //
  1830. if (EqualSign != NULL) {
  1831. //
  1832. // We have ValueName = ValueType ValueData
  1833. //
  1834. //
  1835. // Value name is the beginning of the line, unless
  1836. // it was the special symbol or null
  1837. //
  1838. if (*BeginLine != L'@' && BeginLine != EqualSign) {
  1839. ParsedLine->ValueName = BeginLine;
  1840. }
  1841. //
  1842. // Skip any blanks after the equal sign.
  1843. //
  1844. while (*++EqualSign && *EqualSign <= L' ') {
  1845. }
  1846. //
  1847. // If all that is left is the DELETE keyword, then
  1848. // tell the caller
  1849. //
  1850. if (!_wcsicmp( L"DELETE", EqualSign )) {
  1851. ParsedLine->DeleteValue = TRUE;
  1852. return TRUE;
  1853. }
  1854. else {
  1855. //
  1856. // Otherwise parse the data after the equal sign.
  1857. //
  1858. ParsedLine->ValueString = EqualSign;
  1859. return RTParseValueData( UnicodeFile,
  1860. ParsedLine,
  1861. ValueBuffer,
  1862. ValueBufferSize,
  1863. &ParsedLine->ValueType,
  1864. &ParsedLine->ValueData,
  1865. &ParsedLine->ValueLength
  1866. );
  1867. }
  1868. }
  1869. else {
  1870. //
  1871. // We have a key name. Tell the caller and handle any
  1872. // security descriptor info if present.
  1873. //
  1874. ParsedLine->IsKeyName = TRUE;
  1875. ParsedLine->KeyName = BeginLine;
  1876. if (AclBracket != NULL) {
  1877. //
  1878. // We have found an ACL name
  1879. //
  1880. AclStart = ++AclBracket;
  1881. ParsedLine->AclString = AclStart;
  1882. while (*AclBracket != UNICODE_NULL && *AclBracket != ACL_LIST_END) {
  1883. AclBracket += 1;
  1884. }
  1885. if (*AclBracket != ACL_LIST_END) {
  1886. return FALSE;
  1887. }
  1888. *AclBracket = UNICODE_NULL;
  1889. if (!_wcsicmp( L"DELETE", AclStart )) {
  1890. ParsedLine->DeleteKey = TRUE;
  1891. }
  1892. else {
  1893. ParsedLine->SecurityDescriptor = &ParsedLine->SecurityDescriptorBuffer;
  1894. if (!RegCreateSecurity( AclStart, ParsedLine->SecurityDescriptor )) {
  1895. ParsedLine->SecurityDescriptor = NULL;
  1896. return FALSE;
  1897. }
  1898. }
  1899. }
  1900. return TRUE;
  1901. }
  1902. }
  1903. else {
  1904. UnicodeFile->NextLineNumber += 1;
  1905. }
  1906. }
  1907. return FALSE;
  1908. }
  1909. BOOLEAN
  1910. RTParseValueData(
  1911. IN OUT PREG_UNICODE_FILE UnicodeFile,
  1912. IN OUT PREG_UNICODE_PARSE ParsedLine,
  1913. IN PVOID ValueBuffer,
  1914. IN ULONG ValueBufferSize,
  1915. OUT PULONG ValueType,
  1916. OUT PVOID *ValueData,
  1917. OUT PULONG ValueLength
  1918. )
  1919. {
  1920. PWSTR ValueString;
  1921. ULONG PrefixLength, MaximumValueLength;
  1922. PULONG p;
  1923. PWSTR s, Src, Dst;
  1924. ULONG i, n, cchValue;
  1925. BOOLEAN BackwardsCompatibleInput = FALSE;
  1926. BOOLEAN GetDataFromBinaryFile = FALSE;
  1927. BOOLEAN GetDataFromMultiSzFile = FALSE;
  1928. BOOLEAN ParseDateTime = FALSE;
  1929. if (UnicodeFile != NULL) {
  1930. BackwardsCompatibleInput = UnicodeFile->BackwardsCompatibleInput;
  1931. }
  1932. ValueString = ParsedLine->ValueString;
  1933. *ValueData = NULL;
  1934. *ValueLength = 0;
  1935. *ValueType = REG_SZ;
  1936. for (i=0; RegTypeNameTable[i].TypeName != NULL; i++) {
  1937. PrefixLength = wcslen( RegTypeNameTable[i].TypeName );
  1938. if (ValueString[ PrefixLength ] <= L' ' &&
  1939. !_wcsnicmp( RegTypeNameTable[i].TypeName,
  1940. ValueString,
  1941. PrefixLength
  1942. )
  1943. ) {
  1944. *ValueType = RegTypeNameTable[i].ValueType;
  1945. GetDataFromBinaryFile = RegTypeNameTable[i].GetDataFromBinaryFile;
  1946. GetDataFromMultiSzFile = RegTypeNameTable[i].GetDataFromMultiSzFile;
  1947. ParseDateTime = RegTypeNameTable[i].ParseDateTime;
  1948. break;
  1949. }
  1950. }
  1951. if (RegTypeNameTable[i].TypeName != NULL) {
  1952. ValueString += PrefixLength;
  1953. while (*ValueString != UNICODE_NULL && *ValueString <= L' ') {
  1954. ValueString += 1;
  1955. }
  1956. }
  1957. if (GetDataFromMultiSzFile) {
  1958. *ValueData = ValueBuffer;
  1959. *ValueLength = ValueBufferSize;
  1960. return RegReadMultiSzFile( ParsedLine,
  1961. BackwardsCompatibleInput,
  1962. ValueString,
  1963. ValueBuffer,
  1964. ValueLength
  1965. );
  1966. }
  1967. if (GetDataFromBinaryFile) {
  1968. *ValueData = ValueBuffer;
  1969. *ValueLength = ValueBufferSize;
  1970. return RegReadBinaryFile( ParsedLine,
  1971. ValueString,
  1972. ValueBuffer,
  1973. ValueLength
  1974. );
  1975. }
  1976. cchValue = wcslen( ValueString );
  1977. Src = ValueString;
  1978. switch( *ValueType ) {
  1979. case REG_SZ:
  1980. case REG_EXPAND_SZ:
  1981. //
  1982. // Strip off any surrounding quote characters
  1983. //
  1984. if (cchValue > 1 && Src[ 0 ] == Src[ cchValue - 1 ] &&
  1985. (Src[ 0 ] == L'"' || Src[ 0 ] == L'\'')
  1986. ) {
  1987. Src += 1;
  1988. cchValue -= 2;
  1989. }
  1990. //
  1991. // Fall through after stripping any quotes.
  1992. //
  1993. case REG_LINK:
  1994. *ValueLength = (cchValue + 1) * sizeof( WCHAR );
  1995. if (*ValueLength > ValueBufferSize) {
  1996. SetLastError( ERROR_BUFFER_OVERFLOW );
  1997. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  1998. return FALSE;
  1999. }
  2000. *ValueData = ValueBuffer;
  2001. RtlMoveMemory( *ValueData, Src, *ValueLength );
  2002. *((PWSTR)*ValueData + cchValue) = UNICODE_NULL;
  2003. return TRUE;
  2004. case REG_DWORD:
  2005. *ValueData = ValueBuffer;
  2006. *ValueLength = sizeof( ULONG );
  2007. for (i=0; RegValueNameTable[i].ValueName != NULL; i++) {
  2008. PrefixLength = wcslen( RegValueNameTable[i].ValueName );
  2009. if (!_wcsnicmp( RegValueNameTable[i].ValueName,
  2010. ValueString,
  2011. PrefixLength
  2012. )
  2013. ) {
  2014. *(PULONG)*ValueData = RegValueNameTable[i].Value;
  2015. return TRUE;
  2016. }
  2017. }
  2018. return RegUnicodeToDWORD( &Src, 0, (PULONG)*ValueData );
  2019. case REG_BINARY:
  2020. if (ParseDateTime) {
  2021. #define NUMBER_DATE_TIME_FIELDS 6
  2022. ULONG FieldIndexes[ NUMBER_DATE_TIME_FIELDS ] = {1, 2, 0, 3, 4, 7};
  2023. //
  2024. // Month/Day/Year HH:MM DayOfWeek
  2025. //
  2026. ULONG CurrentField = 0;
  2027. PCSHORT Fields;
  2028. TIME_FIELDS DateTimeFields;
  2029. PWSTR Field;
  2030. ULONG FieldValue;
  2031. RtlZeroMemory( &DateTimeFields, sizeof( DateTimeFields ) );
  2032. Fields = &DateTimeFields.Year;
  2033. while (cchValue) {
  2034. if (CurrentField >= 7) {
  2035. return( FALSE );
  2036. }
  2037. while (cchValue && *Src == L' ') {
  2038. cchValue--;
  2039. Src += 1;
  2040. }
  2041. Field = Src;
  2042. while (cchValue) {
  2043. if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
  2044. }
  2045. else
  2046. if (*Src < L'0' || *Src > L'9') {
  2047. break;
  2048. }
  2049. cchValue--;
  2050. Src += 1;
  2051. }
  2052. if (cchValue) {
  2053. cchValue--;
  2054. Src += 1;
  2055. }
  2056. if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
  2057. if (cchValue < 3) {
  2058. SetLastError( ERROR_INVALID_PARAMETER );
  2059. ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
  2060. return FALSE;
  2061. }
  2062. if (DateTimeFields.Year != 0) {
  2063. SetLastError( ERROR_INVALID_PARAMETER );
  2064. ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
  2065. return FALSE;
  2066. }
  2067. if (!_wcsnicmp( Field, L"SUN", 3 )) {
  2068. FieldValue = 0;
  2069. }
  2070. else
  2071. if (!_wcsnicmp( Field, L"MON", 3 )) {
  2072. FieldValue = 1;
  2073. }
  2074. else
  2075. if (!_wcsnicmp( Field, L"TUE", 3 )) {
  2076. FieldValue = 2;
  2077. }
  2078. else
  2079. if (!_wcsnicmp( Field, L"WED", 3 )) {
  2080. FieldValue = 3;
  2081. }
  2082. else
  2083. if (!_wcsnicmp( Field, L"THU", 3 )) {
  2084. FieldValue = 4;
  2085. }
  2086. else
  2087. if (!_wcsnicmp( Field, L"FRI", 3 )) {
  2088. FieldValue = 5;
  2089. }
  2090. else
  2091. if (!_wcsnicmp( Field, L"SAT", 3 )) {
  2092. FieldValue = 6;
  2093. }
  2094. else {
  2095. SetLastError( ERROR_INVALID_PARAMETER );
  2096. return FALSE;
  2097. }
  2098. }
  2099. else
  2100. if (!RegUnicodeToDWORD( &Field, 0, &FieldValue )) {
  2101. ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
  2102. return FALSE;
  2103. }
  2104. Fields[ FieldIndexes[ CurrentField++ ] ] = (CSHORT)FieldValue;
  2105. }
  2106. if (DateTimeFields.Year == 0) {
  2107. if (DateTimeFields.Day > 5) {
  2108. SetLastError( ERROR_INVALID_PARAMETER );
  2109. ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid;
  2110. return FALSE;
  2111. }
  2112. }
  2113. else
  2114. if (DateTimeFields.Year < 100) {
  2115. DateTimeFields.Year += 1900;
  2116. }
  2117. *ValueLength = sizeof( DateTimeFields );
  2118. if (*ValueLength > ValueBufferSize) {
  2119. SetLastError( ERROR_BUFFER_OVERFLOW );
  2120. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  2121. return FALSE;
  2122. }
  2123. *ValueData = ValueBuffer;
  2124. RtlMoveMemory( *ValueData, &DateTimeFields, sizeof( DateTimeFields ) );
  2125. return TRUE;
  2126. }
  2127. case REG_RESOURCE_LIST:
  2128. case REG_RESOURCE_REQUIREMENTS_LIST:
  2129. case REG_FULL_RESOURCE_DESCRIPTOR:
  2130. case REG_NONE:
  2131. if (!RegUnicodeToDWORD( &Src, 0, ValueLength )) {
  2132. ParsedLine->ParseFailureReason = ParseFailBinaryDataLengthMissing;
  2133. return FALSE;
  2134. }
  2135. if (*ValueLength >= ValueBufferSize) {
  2136. SetLastError( ERROR_BUFFER_OVERFLOW );
  2137. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  2138. return FALSE;
  2139. }
  2140. //
  2141. // Calculate number of DWORD's of data based on specified byte count
  2142. //
  2143. n = (*ValueLength + sizeof( ULONG ) - 1) / sizeof( ULONG );
  2144. //
  2145. // Store converted binary data in ValueBuffer
  2146. //
  2147. *ValueData = ValueBuffer;
  2148. p = ValueBuffer;
  2149. //
  2150. // Src points to remaining text to convert.
  2151. //
  2152. while (n--) {
  2153. if (!RegUnicodeToDWORD( &Src, 0, p )) {
  2154. if (BackwardsCompatibleInput) {
  2155. Src = UnicodeFile->NextLine;
  2156. s = Src;
  2157. while (TRUE) {
  2158. if (*s == '\n') {
  2159. *s = UNICODE_NULL;
  2160. UnicodeFile->NextLineNumber += 1;
  2161. break;
  2162. }
  2163. else
  2164. if (s >= UnicodeFile->EndOfFile || *s == UNICODE_NULL) {
  2165. UnicodeFile->NextLine = NULL;
  2166. ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough;
  2167. SetLastError( ERROR_MORE_DATA );
  2168. return FALSE;
  2169. }
  2170. else {
  2171. break;
  2172. }
  2173. }
  2174. UnicodeFile->NextLine = s + 1;
  2175. n += 1;
  2176. }
  2177. else {
  2178. if (p == ValueBuffer) {
  2179. ParsedLine->ParseFailureReason = ParseFailBinaryDataOmitted;
  2180. SetLastError( ERROR_NO_DATA );
  2181. }
  2182. else {
  2183. ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough;
  2184. SetLastError( ERROR_MORE_DATA );
  2185. }
  2186. return FALSE;
  2187. }
  2188. }
  2189. else {
  2190. p += 1;
  2191. }
  2192. }
  2193. return TRUE;
  2194. case REG_MULTI_SZ:
  2195. *ValueLength = 0;
  2196. *ValueData = ValueBuffer;
  2197. MaximumValueLength = ValueBufferSize;
  2198. Dst = *ValueData;
  2199. while (RegGetMultiString( BackwardsCompatibleInput,
  2200. &Src,
  2201. &Dst,
  2202. MaximumValueLength,
  2203. ValueLength
  2204. )
  2205. ) {
  2206. }
  2207. if (GetLastError() == NO_ERROR) {
  2208. return TRUE;
  2209. }
  2210. else {
  2211. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  2212. return FALSE;
  2213. }
  2214. break;
  2215. default:
  2216. SetLastError( ERROR_INVALID_PARAMETER );
  2217. ParsedLine->ParseFailureReason = ParseFailInvalidRegistryType;
  2218. return FALSE;
  2219. }
  2220. }
  2221. BOOLEAN
  2222. RegGetMultiString(
  2223. IN BOOLEAN BackwardsCompatibleInput,
  2224. IN OUT PWSTR *ValueString,
  2225. IN OUT PWSTR *ValueData,
  2226. IN ULONG MaximumValueLength,
  2227. IN OUT PULONG ValueLength
  2228. )
  2229. /*++
  2230. Routine Description:
  2231. This routine parses multi-strings of the form
  2232. "foo" "bar" "bletch"
  2233. Each time it is called, it strips the first string in quotes from
  2234. the input string, and returns it as the multi-string.
  2235. INPUT ValueString: "foo" "bar" "bletch"
  2236. OUTPUT ValueString: "bar" "bletch"
  2237. ValueData: foo
  2238. Arguments:
  2239. BackwardsCompatibleInput - TRUE if supporting old format input
  2240. ValueString - Supplies the string from which the multi-string will be
  2241. parsed
  2242. - Returns the remaining string after the multi-string is
  2243. removed
  2244. ValueData - Supplies the location where the removed multi-string is
  2245. to be stored.
  2246. - Returns the location to the first byte after the returned
  2247. multi-string
  2248. MaximumValueLength - Supplies the maximum length of data that can be
  2249. stored in ValueData.
  2250. ValueLength - Supplies a pointer to the current length of data stored
  2251. in ValueData.
  2252. - Returns the size of the
  2253. Return Value:
  2254. TRUE if successful and FALSE if not.
  2255. --*/
  2256. {
  2257. PWSTR Src, Dst;
  2258. ULONG n;
  2259. BOOLEAN Result;
  2260. //
  2261. // Find the first quote mark.
  2262. //
  2263. Src = *ValueString;
  2264. while (*Src != UNICODE_NULL && *Src != L'"') {
  2265. Src += 1;
  2266. }
  2267. Dst = *ValueData;
  2268. if (*Src == UNICODE_NULL) {
  2269. SetLastError( NO_ERROR );
  2270. Result = FALSE;
  2271. }
  2272. else {
  2273. //
  2274. // We have found the start of the multi-string. Now find the end,
  2275. // building up our return ValueData as we go.
  2276. //
  2277. Src += 1;
  2278. while (*Src != UNICODE_NULL) {
  2279. if (*Src == L'"') {
  2280. if (!BackwardsCompatibleInput &&
  2281. Src[1] == L'"'
  2282. ) {
  2283. Src += 1;
  2284. }
  2285. else {
  2286. *Src++ = UNICODE_NULL;
  2287. break;
  2288. }
  2289. }
  2290. *ValueLength += sizeof( WCHAR );
  2291. if (*ValueLength >= MaximumValueLength) {
  2292. SetLastError( ERROR_BUFFER_OVERFLOW );
  2293. return FALSE;
  2294. }
  2295. *Dst++ = *Src++;
  2296. }
  2297. Result = TRUE;
  2298. }
  2299. *ValueLength += sizeof( WCHAR );
  2300. if (*ValueLength >= MaximumValueLength) {
  2301. SetLastError( ERROR_BUFFER_OVERFLOW );
  2302. return FALSE;
  2303. }
  2304. *Dst++ = UNICODE_NULL;
  2305. *ValueData = Dst;
  2306. *ValueString = Src;
  2307. return Result;
  2308. }
  2309. BOOLEAN
  2310. RegReadMultiSzFile(
  2311. IN OUT PREG_UNICODE_PARSE ParsedLine,
  2312. IN BOOLEAN BackwardsCompatibleInput,
  2313. IN PWSTR FileName,
  2314. IN OUT PVOID ValueData,
  2315. IN OUT PULONG ValueLength
  2316. )
  2317. {
  2318. PWSTR Src, Dst;
  2319. REG_UNICODE_FILE MultiSzFile;
  2320. ULONG MaximumValueLength;
  2321. BOOLEAN Result;
  2322. if (!RTLoadAsciiFileAsUnicode( FileName, &MultiSzFile )) {
  2323. ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile;
  2324. return FALSE;
  2325. }
  2326. MaximumValueLength = *ValueLength;
  2327. *ValueLength = 0;
  2328. Src = MultiSzFile.NextLine;
  2329. Dst = ValueData;
  2330. while (RegGetMultiString( BackwardsCompatibleInput,
  2331. &Src,
  2332. &Dst,
  2333. MaximumValueLength,
  2334. ValueLength
  2335. )
  2336. ) {
  2337. }
  2338. if (GetLastError() == NO_ERROR) {
  2339. Result = TRUE;
  2340. }
  2341. else {
  2342. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  2343. Result = FALSE;
  2344. }
  2345. RTUnloadUnicodeFile( &MultiSzFile );
  2346. return Result;
  2347. }
  2348. BOOLEAN
  2349. RegReadBinaryFile(
  2350. IN OUT PREG_UNICODE_PARSE ParsedLine,
  2351. IN PWSTR FileName,
  2352. IN OUT PVOID ValueData,
  2353. IN OUT PULONG ValueLength
  2354. )
  2355. {
  2356. BOOLEAN Result;
  2357. HANDLE File;
  2358. DWORD FileSize, FileSizeHigh;
  2359. DWORD BytesRead;
  2360. File = CreateFile( FileName,
  2361. FILE_GENERIC_READ,
  2362. FILE_SHARE_DELETE |
  2363. FILE_SHARE_READ |
  2364. FILE_SHARE_WRITE,
  2365. NULL,
  2366. OPEN_EXISTING,
  2367. 0,
  2368. NULL
  2369. );
  2370. if (File == INVALID_HANDLE_VALUE) {
  2371. ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile;
  2372. return FALSE;
  2373. }
  2374. ParsedLine->ParseFailureReason = ParseFailValueTooLarge;
  2375. FileSize = GetFileSize( File, &FileSizeHigh );
  2376. if (FileSizeHigh != 0 ||
  2377. FileSize == INVALID_FILE_SIZE ||
  2378. FileSize >= *ValueLength
  2379. ) {
  2380. CloseHandle( File );
  2381. SetLastError( ERROR_BUFFER_OVERFLOW );
  2382. return FALSE;
  2383. }
  2384. Result = FALSE;
  2385. if (ReadFile( File, ValueData, FileSize, &BytesRead, NULL )) {
  2386. if (BytesRead != FileSize) {
  2387. SetLastError( ERROR_HANDLE_EOF );
  2388. }
  2389. else {
  2390. ParsedLine->ParseFailureReason = ParseFailNoFailure;
  2391. *ValueLength = FileSize;
  2392. Result = TRUE;
  2393. }
  2394. }
  2395. CloseHandle( File );
  2396. return Result;
  2397. }
  2398. BOOLEAN
  2399. NeedQuotedString(
  2400. PWSTR Name,
  2401. PWSTR Value,
  2402. PWCHAR QuoteChar
  2403. )
  2404. {
  2405. ULONG i;
  2406. if (Name != NULL) {
  2407. if (*Name != UNICODE_NULL &&
  2408. (*Name == L' ' || Name[ wcslen( Name ) - 1 ] == L' ')
  2409. ) {
  2410. *QuoteChar = '"';
  2411. return TRUE;
  2412. }
  2413. else {
  2414. return FALSE;
  2415. }
  2416. }
  2417. else {
  2418. i = wcslen( Value ) - 1;
  2419. if (*Value != UNICODE_NULL) {
  2420. if ((*Value == L' ' || Value[ i ] == L' ' || Value[ i ] == L'\\')) {
  2421. *QuoteChar = '"';
  2422. return TRUE;
  2423. }
  2424. else
  2425. if (*Value == L'"' && Value[ i ] == L'"') {
  2426. *QuoteChar = '\'';
  2427. return TRUE;
  2428. }
  2429. else
  2430. if (*Value == L'\'' && Value[ i ] == L'\'') {
  2431. *QuoteChar = '"';
  2432. return TRUE;
  2433. }
  2434. }
  2435. return FALSE;
  2436. }
  2437. }
  2438. void
  2439. RTFormatKeyName(
  2440. PREG_OUTPUT_ROUTINE OutputRoutine,
  2441. PVOID OutputRoutineParameter,
  2442. ULONG IndentLevel,
  2443. PWSTR KeyName
  2444. )
  2445. {
  2446. PWSTR pw;
  2447. WCHAR QuoteChar;
  2448. if (NeedQuotedString( KeyName, NULL, &QuoteChar )) {
  2449. (OutputRoutine)( OutputRoutineParameter,
  2450. "%.*s%c%ws%c",
  2451. IndentLevel,
  2452. BlanksForPadding,
  2453. QuoteChar,
  2454. KeyName,
  2455. QuoteChar
  2456. );
  2457. }
  2458. else {
  2459. (OutputRoutine)( OutputRoutineParameter,
  2460. "%.*s%ws",
  2461. IndentLevel,
  2462. BlanksForPadding,
  2463. KeyName
  2464. );
  2465. }
  2466. return;
  2467. }
  2468. void
  2469. RTFormatKeySecurity(
  2470. PREG_OUTPUT_ROUTINE OutputRoutine,
  2471. PVOID OutputRoutineParameter,
  2472. HKEY KeyHandle,
  2473. PSECURITY_DESCRIPTOR SecurityDescriptor
  2474. )
  2475. {
  2476. ULONG SecurityBufferLength;
  2477. BOOLEAN FormattedAces;
  2478. WCHAR AceList[ 256 ];
  2479. FormattedAces = FALSE;
  2480. if (KeyHandle != NULL)
  2481. {
  2482. SecurityBufferLength = 0;
  2483. if (RegGetKeySecurity( KeyHandle,
  2484. DACL_SECURITY_INFORMATION,
  2485. SecurityDescriptor,
  2486. &SecurityBufferLength
  2487. ) == ERROR_INSUFFICIENT_BUFFER )
  2488. {
  2489. SecurityDescriptor = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(),
  2490. 0,
  2491. SecurityBufferLength
  2492. );
  2493. if (SecurityDescriptor)
  2494. {
  2495. if (RegGetKeySecurity( KeyHandle,
  2496. DACL_SECURITY_INFORMATION,
  2497. SecurityDescriptor,
  2498. &SecurityBufferLength
  2499. ) != NO_ERROR ) {
  2500. HeapFree( GetProcessHeap(), 0, SecurityDescriptor );
  2501. } else {
  2502. FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList );
  2503. HeapFree( GetProcessHeap(), 0, SecurityDescriptor );
  2504. }
  2505. }
  2506. }
  2507. }
  2508. else
  2509. if (SecurityDescriptor != NULL) {
  2510. FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList );
  2511. }
  2512. if (FormattedAces) {
  2513. (OutputRoutine)( OutputRoutineParameter,
  2514. " %wc%ws%wc",
  2515. ACL_LIST_START,
  2516. AceList,
  2517. ACL_LIST_END
  2518. );
  2519. }
  2520. return;
  2521. }
  2522. void
  2523. RegDisplayResourceListAsComment(
  2524. ULONG OutputWidth,
  2525. PREG_OUTPUT_ROUTINE OutputRoutine,
  2526. PVOID OutputRoutineParameter,
  2527. ULONG IndentLevel,
  2528. ULONG ValueLength,
  2529. ULONG ValueType,
  2530. PWSTR ValueData
  2531. );
  2532. void
  2533. RTFormatKeyValue(
  2534. ULONG OutputWidth,
  2535. PREG_OUTPUT_ROUTINE OutputRoutine,
  2536. PVOID OutputRoutineParameter,
  2537. BOOLEAN SummaryOutput,
  2538. ULONG IndentLevel,
  2539. PWSTR ValueName,
  2540. ULONG ValueLength,
  2541. ULONG ValueType,
  2542. PWSTR ValueData
  2543. )
  2544. {
  2545. PULONG p;
  2546. PWSTR pw, pw1, pwBreak;
  2547. WCHAR QuoteChar, BreakChar;
  2548. ULONG i, j, k, m, cbPrefix, cb;
  2549. PUCHAR pbyte;
  2550. char eol[11];
  2551. cbPrefix = (OutputRoutine)( OutputRoutineParameter,
  2552. "%.*s",
  2553. IndentLevel,
  2554. BlanksForPadding
  2555. );
  2556. if (ValueName != NULL && *ValueName != UNICODE_NULL) {
  2557. if (NeedQuotedString( ValueName, NULL, &QuoteChar )) {
  2558. cbPrefix += (OutputRoutine)( OutputRoutineParameter,
  2559. "%c%ws%c ",
  2560. QuoteChar,
  2561. ValueName,
  2562. QuoteChar
  2563. );
  2564. }
  2565. else {
  2566. cbPrefix += (OutputRoutine)( OutputRoutineParameter, "%ws ", ValueName );
  2567. }
  2568. }
  2569. cbPrefix += (OutputRoutine)( OutputRoutineParameter, "= " );
  2570. switch( ValueType ) {
  2571. case REG_SZ:
  2572. case REG_EXPAND_SZ:
  2573. if (ValueType == REG_EXPAND_SZ) {
  2574. cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_EXPAND_SZ " );
  2575. }
  2576. pw = (PWSTR)ValueData;
  2577. if (ValueLength & (sizeof(WCHAR)-1)) {
  2578. (OutputRoutine)( OutputRoutineParameter, "(*** Length not multiple of WCHAR ***)" );
  2579. ValueLength = (ValueLength+sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1);
  2580. }
  2581. if (ValueLength == 0 ||
  2582. *(PWSTR)((PCHAR)pw + ValueLength - sizeof( WCHAR )) != UNICODE_NULL
  2583. ) {
  2584. (OutputRoutine)( OutputRoutineParameter, "(*** MISSING TRAILING NULL CHARACTER ***)" );
  2585. *(PWSTR)((PCHAR)pw + ValueLength) = UNICODE_NULL;
  2586. }
  2587. if (NeedQuotedString( NULL, pw, &QuoteChar )) {
  2588. (OutputRoutine)( OutputRoutineParameter, "%c%ws%c", QuoteChar, pw, QuoteChar );
  2589. }
  2590. else
  2591. if ((cbPrefix + wcslen(pw)) <= OutputWidth) {
  2592. (OutputRoutine)( OutputRoutineParameter, "%ws", pw );
  2593. }
  2594. else {
  2595. while (*pw) {
  2596. pw1 = pw;
  2597. pwBreak = NULL;
  2598. while (*pw1 && *pw1 >= L' ') {
  2599. if ((cbPrefix + (ULONG)(pw1 - pw)) > (OutputWidth-4)) {
  2600. break;
  2601. }
  2602. if (wcschr( L" ,;", *pw1 )) {
  2603. pwBreak = pw1;
  2604. }
  2605. pw1++;
  2606. }
  2607. if (pwBreak != NULL) {
  2608. while (*pwBreak == pwBreak[1]) {
  2609. pwBreak += 1;
  2610. }
  2611. pw1 = pwBreak + 1;
  2612. }
  2613. else {
  2614. while (*pw1) {
  2615. pw1 += 1;
  2616. }
  2617. }
  2618. (OutputRoutine)( OutputRoutineParameter, "%.*ws", pw1 - pw, pw );
  2619. if (*pw1 == UNICODE_NULL) {
  2620. break;
  2621. }
  2622. if (SummaryOutput) {
  2623. (OutputRoutine)( OutputRoutineParameter, "\\..." );
  2624. break;
  2625. }
  2626. (OutputRoutine)( OutputRoutineParameter,
  2627. "\\\n%.*s",
  2628. IndentLevel == 0 ? 4 : cbPrefix,
  2629. BlanksForPadding
  2630. );
  2631. pw = pw1;
  2632. }
  2633. }
  2634. (OutputRoutine)( OutputRoutineParameter, "\n" );
  2635. break;
  2636. case REG_RESOURCE_LIST:
  2637. case REG_FULL_RESOURCE_DESCRIPTOR:
  2638. case REG_RESOURCE_REQUIREMENTS_LIST:
  2639. case REG_BINARY:
  2640. case REG_NONE:
  2641. switch( ValueType ) {
  2642. case REG_NONE:
  2643. pw = L"REG_NONE";
  2644. break;
  2645. case REG_BINARY:
  2646. pw = L"REG_BINARY";
  2647. break;
  2648. case REG_RESOURCE_REQUIREMENTS_LIST:
  2649. pw = L"REG_RESOURCE_REQUIREMENTS_LIST";
  2650. break;
  2651. case REG_RESOURCE_LIST:
  2652. pw = L"REG_RESOURCE_LIST";
  2653. break;
  2654. case REG_FULL_RESOURCE_DESCRIPTOR:
  2655. pw = L"REG_FULL_RESOURCE_DESCRIPTOR";
  2656. break;
  2657. }
  2658. cb = (OutputRoutine)( OutputRoutineParameter, "%ws 0x%08lx", pw, ValueLength );
  2659. if (ValueLength != 0) {
  2660. p = (PULONG)ValueData;
  2661. i = (ValueLength + 3) / sizeof( ULONG );
  2662. if (!SummaryOutput || i <= 2) {
  2663. for (j=0; j<i; j++) {
  2664. if ((cbPrefix + cb + 11) > (OutputWidth - 2)) {
  2665. (OutputRoutine)( OutputRoutineParameter,
  2666. " \\\n%.*s",
  2667. IndentLevel == 0 ? 4 : cbPrefix,
  2668. BlanksForPadding
  2669. );
  2670. cb = 0;
  2671. }
  2672. else {
  2673. cb += (OutputRoutine)( OutputRoutineParameter, " " );
  2674. }
  2675. cb += (OutputRoutine)( OutputRoutineParameter, "0x%08lx", *p++ );
  2676. }
  2677. }
  2678. else {
  2679. (OutputRoutine)( OutputRoutineParameter, " \\..." );
  2680. }
  2681. }
  2682. (OutputRoutine)( OutputRoutineParameter, "\n" );
  2683. if (!SummaryOutput) {
  2684. RegDisplayResourceListAsComment( OutputWidth,
  2685. OutputRoutine,
  2686. OutputRoutineParameter,
  2687. IndentLevel,
  2688. ValueLength,
  2689. ValueType,
  2690. ValueData
  2691. );
  2692. }
  2693. break;
  2694. // case REG_DWORD_LITTLE_ENDIAN:
  2695. case REG_DWORD:
  2696. (OutputRoutine)( OutputRoutineParameter, "REG_DWORD 0x%08lx\n",
  2697. *(PULONG)ValueData
  2698. );
  2699. break;
  2700. case REG_DWORD_BIG_ENDIAN:
  2701. (OutputRoutine)( OutputRoutineParameter, "REG_DWORD_BIG_ENDIAN 0x%08lx\n",
  2702. *(PULONG)ValueData
  2703. );
  2704. break;
  2705. case REG_LINK:
  2706. (OutputRoutine)( OutputRoutineParameter, "REG_LINK %ws\n",
  2707. (PWSTR)ValueData
  2708. );
  2709. break;
  2710. case REG_MULTI_SZ:
  2711. (!FullPathOutput) ? strcpy (eol, " \\\n%.*s") : strcpy (eol, " \\ ->%.*s");
  2712. cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_MULTI_SZ " );
  2713. pw = (PWSTR)ValueData;
  2714. i = 0;
  2715. if (*pw)
  2716. while (i < (ValueLength - 1) / sizeof( WCHAR )) {
  2717. if (i > 0) {
  2718. (OutputRoutine)( OutputRoutineParameter,
  2719. eol,
  2720. IndentLevel == 0 ? 4 : cbPrefix,
  2721. BlanksForPadding
  2722. );
  2723. }
  2724. (OutputRoutine)( OutputRoutineParameter, "\"");
  2725. do {
  2726. if (pw[i] == '"') {
  2727. (OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]);
  2728. }
  2729. (OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]);
  2730. ++i;
  2731. }
  2732. while ( pw[i] != UNICODE_NULL );
  2733. (OutputRoutine)( OutputRoutineParameter, "\" ");
  2734. if (SummaryOutput) {
  2735. (OutputRoutine)( OutputRoutineParameter, " \\..." );
  2736. break;
  2737. }
  2738. ++i;
  2739. }
  2740. (OutputRoutine)( OutputRoutineParameter, "\n" );
  2741. break;
  2742. default:
  2743. (OutputRoutine)( OutputRoutineParameter, "*** Unknown Registry Data Type (%08lx) Length: 0x%lx\n",
  2744. ValueType,
  2745. ValueLength
  2746. );
  2747. break;
  2748. }
  2749. return;
  2750. }
  2751. void
  2752. RegDisplayResourceListAsComment(
  2753. ULONG OutputWidth,
  2754. PREG_OUTPUT_ROUTINE OutputRoutine,
  2755. PVOID OutputRoutineParameter,
  2756. ULONG IndentLevel,
  2757. ULONG ValueLength,
  2758. ULONG ValueType,
  2759. PWSTR ValueData
  2760. )
  2761. {
  2762. PCM_RESOURCE_LIST ResourceList = (PCM_RESOURCE_LIST)ValueData;
  2763. PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
  2764. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
  2765. ULONG i, j, k, l, count, cb;
  2766. PWSTR TypeName;
  2767. PWSTR FlagName;
  2768. ULONG Size = ValueLength;
  2769. PULONG p;
  2770. if (ValueType == REG_RESOURCE_LIST) {
  2771. if (ValueLength < sizeof( *ResourceList )) {
  2772. return;
  2773. }
  2774. count = ResourceList->Count;
  2775. FullDescriptor = &ResourceList->List[0];
  2776. (OutputRoutine)( OutputRoutineParameter,
  2777. ";%.*sNumber of Full resource Descriptors = %d",
  2778. IndentLevel - 1,
  2779. BlanksForPadding,
  2780. count
  2781. );
  2782. }
  2783. else
  2784. if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR) {
  2785. if (ValueLength < sizeof( *FullDescriptor )) {
  2786. return;
  2787. }
  2788. count = 1;
  2789. FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
  2790. }
  2791. else {
  2792. return;
  2793. }
  2794. for (i=0; i< count; i++) {
  2795. (OutputRoutine)( OutputRoutineParameter, "\n;%.*sPartial List number %d\n",
  2796. IndentLevel+4-1,
  2797. BlanksForPadding,
  2798. i
  2799. );
  2800. switch(FullDescriptor->InterfaceType) {
  2801. case InterfaceTypeUndefined: TypeName = L"Undefined";break;
  2802. case Internal: TypeName = L"Internal"; break;
  2803. case Isa: TypeName = L"Isa"; break;
  2804. case Eisa: TypeName = L"Eisa"; break;
  2805. case MicroChannel: TypeName = L"MicroChannel"; break;
  2806. case TurboChannel: TypeName = L"TurboChannel"; break;
  2807. case PCIBus: TypeName = L"PCI"; break;
  2808. case VMEBus: TypeName = L"VME"; break;
  2809. case NuBus: TypeName = L"NuBus"; break;
  2810. case PCMCIABus: TypeName = L"PCMCIA"; break;
  2811. case CBus: TypeName = L"CBUS"; break;
  2812. case MPIBus: TypeName = L"MPI"; break;
  2813. case MPSABus: TypeName = L"MPSA"; break;
  2814. case ProcessorInternal: TypeName = L"ProcessorInternal";break;
  2815. case InternalPowerBus: TypeName = L"InternalPower"; break;
  2816. case PNPISABus: TypeName = L"PNP Isa"; break;
  2817. default:
  2818. TypeName = L"***invalid bus type***";
  2819. break;
  2820. }
  2821. (OutputRoutine)( OutputRoutineParameter, ";%.*sINTERFACE_TYPE %ws\n",
  2822. IndentLevel+8-1,
  2823. BlanksForPadding,
  2824. TypeName
  2825. );
  2826. (OutputRoutine)( OutputRoutineParameter, ";%.*sBUS_NUMBER %d\n",
  2827. IndentLevel+8-1,
  2828. BlanksForPadding,
  2829. FullDescriptor->BusNumber
  2830. );
  2831. //
  2832. // This is a basic test to see if the data format is right.
  2833. // We know at least some video resource list are bogus ...
  2834. //
  2835. if (Size < FullDescriptor->PartialResourceList.Count *
  2836. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) {
  2837. (OutputRoutine)( OutputRoutineParameter, "\n;%.*s *** !!! Invalid ResourceList !!! *** \n",
  2838. IndentLevel+8-1,
  2839. BlanksForPadding,
  2840. i
  2841. );
  2842. break;
  2843. }
  2844. Size -= FullDescriptor->PartialResourceList.Count *
  2845. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  2846. for (j=0; j<FullDescriptor->PartialResourceList.Count; j++) {
  2847. (OutputRoutine)( OutputRoutineParameter, ";%.*sDescriptor number %d\n",
  2848. IndentLevel+12-1,
  2849. BlanksForPadding,
  2850. j
  2851. );
  2852. PartialResourceDescriptor = &(FullDescriptor->PartialResourceList.PartialDescriptors[j]);
  2853. switch(PartialResourceDescriptor->ShareDisposition) {
  2854. case CmResourceShareUndetermined:
  2855. TypeName = L"CmResourceShareUndetermined";
  2856. break;
  2857. case CmResourceShareDeviceExclusive:
  2858. TypeName = L"CmResourceDeviceExclusive";
  2859. break;
  2860. case CmResourceShareDriverExclusive:
  2861. TypeName = L"CmResourceDriverExclusive";
  2862. break;
  2863. case CmResourceShareShared:
  2864. TypeName = L"CmResourceShared";
  2865. break;
  2866. default:
  2867. TypeName = L"***invalid share disposition***";
  2868. break;
  2869. }
  2870. (OutputRoutine)( OutputRoutineParameter, ";%.*sShare Disposition %ws\n",
  2871. IndentLevel+12-1,
  2872. BlanksForPadding,
  2873. TypeName
  2874. );
  2875. FlagName = L"***invalid Flags";
  2876. switch(PartialResourceDescriptor->Type) {
  2877. case CmResourceTypeNull:
  2878. TypeName = L"NULL";
  2879. FlagName = L"***Unused";
  2880. break;
  2881. case CmResourceTypePort:
  2882. TypeName = L"PORT";
  2883. if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_MEMORY) {
  2884. FlagName = L"CM_RESOURCE_PORT_MEMORY";
  2885. }
  2886. if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_IO) {
  2887. FlagName = L"CM_RESOURCE_PORT_IO";
  2888. }
  2889. break;
  2890. case CmResourceTypeInterrupt:
  2891. TypeName = L"INTERRUPT";
  2892. if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
  2893. FlagName = L"CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE";
  2894. }
  2895. if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED) {
  2896. FlagName = L"CM_RESOURCE_INTERRUPT_LATCHED";
  2897. }
  2898. break;
  2899. case CmResourceTypeMemory:
  2900. TypeName = L"MEMORY";
  2901. if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_WRITE) {
  2902. FlagName = L"CM_RESOURCE_MEMORY_READ_WRITE";
  2903. }
  2904. if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_ONLY) {
  2905. FlagName = L"CM_RESOURCE_MEMORY_READ_ONLY";
  2906. }
  2907. if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_WRITE_ONLY) {
  2908. FlagName = L"CM_RESOURCE_MEMORY_WRITE_ONLY";
  2909. }
  2910. break;
  2911. case CmResourceTypeDma:
  2912. TypeName = L"DMA";
  2913. FlagName = L"***Unused";
  2914. break;
  2915. case CmResourceTypeDeviceSpecific:
  2916. TypeName = L"DEVICE SPECIFIC";
  2917. FlagName = L"***Unused";
  2918. break;
  2919. default:
  2920. TypeName = L"***invalid type***";
  2921. break;
  2922. }
  2923. (OutputRoutine)( OutputRoutineParameter, ";%.*sTYPE %ws\n",
  2924. IndentLevel+12-1,
  2925. BlanksForPadding,
  2926. TypeName
  2927. );
  2928. (OutputRoutine)( OutputRoutineParameter, ";%.*sFlags %ws\n",
  2929. IndentLevel+12-1,
  2930. BlanksForPadding,
  2931. FlagName
  2932. );
  2933. switch(PartialResourceDescriptor->Type) {
  2934. case CmResourceTypePort:
  2935. (OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx LENGTH 0x%08lx\n",
  2936. IndentLevel+12-1,
  2937. BlanksForPadding,
  2938. PartialResourceDescriptor->u.Port.Start.LowPart,
  2939. PartialResourceDescriptor->u.Port.Length
  2940. );
  2941. break;
  2942. case CmResourceTypeInterrupt:
  2943. (OutputRoutine)( OutputRoutineParameter, ";%.*sLEVEL %d VECTOR %d AFFINITY %d\n",
  2944. IndentLevel+12-1,
  2945. BlanksForPadding,
  2946. PartialResourceDescriptor->u.Interrupt.Level,
  2947. PartialResourceDescriptor->u.Interrupt.Vector,
  2948. PartialResourceDescriptor->u.Interrupt.Affinity
  2949. );
  2950. break;
  2951. case CmResourceTypeMemory:
  2952. (OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx%08lx LENGTH 0x%08lx\n",
  2953. IndentLevel+12-1,
  2954. BlanksForPadding,
  2955. PartialResourceDescriptor->u.Memory.Start.HighPart,
  2956. PartialResourceDescriptor->u.Memory.Start.LowPart,
  2957. PartialResourceDescriptor->u.Memory.Length
  2958. );
  2959. break;
  2960. case CmResourceTypeDma:
  2961. (OutputRoutine)( OutputRoutineParameter, ";%.*sCHANNEL %d PORT %d\n",
  2962. IndentLevel+12-1,
  2963. BlanksForPadding,
  2964. PartialResourceDescriptor->u.Dma.Channel,
  2965. PartialResourceDescriptor->u.Dma.Port
  2966. );
  2967. break;
  2968. case CmResourceTypeDeviceSpecific:
  2969. cb = (OutputRoutine)( OutputRoutineParameter, ";%.*sDataSize 0x%08lx Data:",
  2970. IndentLevel+12-1,
  2971. BlanksForPadding,
  2972. PartialResourceDescriptor->u.DeviceSpecificData.DataSize
  2973. );
  2974. p = (PULONG)(PartialResourceDescriptor + 1);
  2975. k = (PartialResourceDescriptor->u.DeviceSpecificData.DataSize + 3) / sizeof( ULONG );
  2976. for (l=0; l<k; l++) {
  2977. if ((cb + 11) >= OutputWidth) {
  2978. cb = (OutputRoutine)( OutputRoutineParameter, "\n;%.*s",
  2979. IndentLevel+12-1,
  2980. BlanksForPadding
  2981. ) - 1;
  2982. }
  2983. cb += (OutputRoutine)( OutputRoutineParameter, " 0x%08lx", *p++ );
  2984. }
  2985. (OutputRoutine)( OutputRoutineParameter, "\n" );
  2986. break;
  2987. default:
  2988. (OutputRoutine)( OutputRoutineParameter, ";%.*s*** Unknown resource list type: 0x%x ****\n",
  2989. IndentLevel+12-1,
  2990. BlanksForPadding,
  2991. PartialResourceDescriptor->Type
  2992. );
  2993. break;
  2994. }
  2995. (OutputRoutine)( OutputRoutineParameter, ";\n" );
  2996. }
  2997. FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) (PartialResourceDescriptor+1);
  2998. }
  2999. return;
  3000. }