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

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