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.

713 lines
18 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 "precomp.h"
  13. #pragma hdrstop
  14. LONG
  15. RegLoadHive(
  16. IN PREG_CONTEXT RegistryContext,
  17. IN PWSTR HiveFileName,
  18. IN PWSTR HiveRootName
  19. );
  20. void
  21. RegUnloadHive(
  22. IN PREG_CONTEXT RegistryContext
  23. );
  24. BOOLEAN PrivilegeEnabled;
  25. BOOLEAN RestoreWasEnabled;
  26. BOOLEAN BackupWasEnabled;
  27. BOOLEAN
  28. RTEnableBackupRestorePrivilege( void )
  29. {
  30. NTSTATUS Status;
  31. //
  32. // Try to enable backup and restore privileges
  33. //
  34. Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  35. TRUE, // Enable
  36. FALSE, // Not impersonating
  37. &RestoreWasEnabled // previous state
  38. );
  39. if (!NT_SUCCESS( Status )) {
  40. return FALSE;
  41. }
  42. Status = RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
  43. TRUE, // Enable
  44. FALSE, // Not impersonating
  45. &BackupWasEnabled // previous state
  46. );
  47. if (!NT_SUCCESS( Status )) {
  48. return FALSE;
  49. }
  50. PrivilegeEnabled = TRUE;
  51. return TRUE;
  52. }
  53. void
  54. RTDisableBackupRestorePrivilege( void )
  55. {
  56. //
  57. // Restore privileges to what they were
  58. //
  59. RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  60. RestoreWasEnabled,
  61. FALSE,
  62. &RestoreWasEnabled
  63. );
  64. RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
  65. BackupWasEnabled,
  66. FALSE,
  67. &BackupWasEnabled
  68. );
  69. PrivilegeEnabled = FALSE;
  70. return;
  71. }
  72. LONG
  73. RTConnectToRegistry(
  74. IN PWSTR MachineName,
  75. IN PWSTR HiveFileName,
  76. IN PWSTR HiveRootName,
  77. OUT PWSTR *DefaultRootKeyName,
  78. OUT PREG_CONTEXT RegistryContext
  79. )
  80. {
  81. LONG Error;
  82. if (MachineName != NULL) {
  83. if (HiveRootName || HiveFileName ) {
  84. return ERROR_INVALID_PARAMETER;
  85. }
  86. Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot );
  87. if (Error == NO_ERROR) {
  88. Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot );
  89. if (Error == NO_ERROR) {
  90. Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot );
  91. }
  92. }
  93. if (Error != NO_ERROR) {
  94. if (RegistryContext->MachineRoot != NULL) {
  95. RegCloseKey( RegistryContext->MachineRoot );
  96. RegistryContext->MachineRoot = NULL;
  97. }
  98. if (RegistryContext->UsersRoot != NULL) {
  99. RegCloseKey( RegistryContext->UsersRoot );
  100. RegistryContext->UsersRoot = NULL;
  101. }
  102. return Error;
  103. }
  104. wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
  105. wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
  106. wcscpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default" );
  107. RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY;
  108. }
  109. else if (HiveRootName != NULL || HiveFileName != NULL) {
  110. if (HiveRootName == NULL || HiveFileName == NULL ) {
  111. return ERROR_INVALID_PARAMETER;
  112. }
  113. if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) {
  114. return ERROR_PRIVILEGE_NOT_HELD;
  115. }
  116. RegistryContext->MachineRoot = NULL;
  117. RegistryContext->UsersRoot = NULL;
  118. RegistryContext->CurrentUserRoot = NULL;
  119. Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName );
  120. if (Error != NO_ERROR) {
  121. return Error;
  122. }
  123. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  124. *DefaultRootKeyName = HiveRootName;
  125. }
  126. RegistryContext->Target = REG_TARGET_HIVE_REGISTRY;
  127. }
  128. else {
  129. NTSTATUS Status;
  130. UNICODE_STRING CurrentUserKeyPath;
  131. RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
  132. RegistryContext->UsersRoot = HKEY_USERS;
  133. RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
  134. wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
  135. wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
  136. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  137. if (!NT_SUCCESS( Status )) {
  138. SetLastError( RtlNtStatusToDosError( Status ) );
  139. return FALSE;
  140. }
  141. wcscpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer );
  142. RtlFreeUnicodeString( &CurrentUserKeyPath );
  143. RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY;
  144. }
  145. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  146. *DefaultRootKeyName = L"\\Registry";
  147. }
  148. RegistryContext->MachinePathLength = wcslen( RegistryContext->MachinePath );
  149. RegistryContext->UsersPathLength = wcslen( RegistryContext->UsersPath );
  150. RegistryContext->CurrentUserPathLength = wcslen( RegistryContext->CurrentUserPath );
  151. return NO_ERROR;
  152. }
  153. LONG
  154. RTDisconnectFromRegistry(
  155. IN PREG_CONTEXT RegistryContext
  156. )
  157. {
  158. switch( RegistryContext->Target ) {
  159. case REG_TARGET_DISCONNECTED:
  160. break;
  161. case REG_TARGET_LOCAL_REGISTRY:
  162. break;
  163. case REG_TARGET_REMOTE_REGISTRY:
  164. break;
  165. case REG_TARGET_HIVE_REGISTRY:
  166. RegUnloadHive( RegistryContext );
  167. break;
  168. }
  169. if (PrivilegeEnabled) {
  170. RTDisableBackupRestorePrivilege();
  171. }
  172. RegistryContext->Target = REG_TARGET_DISCONNECTED;
  173. return NO_ERROR;
  174. }
  175. UNICODE_STRING RegHiveRootName;
  176. LONG
  177. RegLoadHive(
  178. IN PREG_CONTEXT RegistryContext,
  179. IN PWSTR HiveFileName,
  180. IN PWSTR HiveRootName
  181. )
  182. {
  183. NTSTATUS Status;
  184. UNICODE_STRING NtFileName;
  185. OBJECT_ATTRIBUTES File;
  186. if (!RtlDosPathNameToNtPathName_U( HiveFileName,
  187. &NtFileName,
  188. NULL,
  189. NULL
  190. )
  191. ) {
  192. return ERROR_BAD_PATHNAME;
  193. }
  194. InitializeObjectAttributes( &File,
  195. &NtFileName,
  196. OBJ_CASE_INSENSITIVE,
  197. NULL,
  198. NULL
  199. );
  200. RtlInitUnicodeString( &RegHiveRootName, L"\\Registry");
  201. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  202. &RegHiveRootName,
  203. OBJ_CASE_INSENSITIVE,
  204. NULL,
  205. NULL
  206. );
  207. Status = NtOpenKey( &RegistryContext->HiveRootHandle,
  208. MAXIMUM_ALLOWED,
  209. &RegistryContext->HiveRootKey
  210. );
  211. RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
  212. if (!NT_SUCCESS(Status)) {
  213. return RtlNtStatusToDosError( Status );
  214. }
  215. RtlInitUnicodeString( &RegHiveRootName, HiveRootName );
  216. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  217. &RegHiveRootName,
  218. OBJ_CASE_INSENSITIVE,
  219. RegistryContext->HiveRootHandle,
  220. NULL
  221. );
  222. NtUnloadKey( &RegistryContext->HiveRootKey );
  223. Status = NtLoadKey( &RegistryContext->HiveRootKey, &File );
  224. if (!NT_SUCCESS( Status )) {
  225. return RtlNtStatusToDosError( Status );
  226. }
  227. return NO_ERROR;
  228. }
  229. void
  230. RegUnloadHive(
  231. IN PREG_CONTEXT RegistryContext
  232. )
  233. {
  234. NTSTATUS Status;
  235. HANDLE Handle;
  236. PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
  237. Status = NtOpenKey( &Handle,
  238. MAXIMUM_ALLOWED,
  239. &RegistryContext->HiveRootKey
  240. );
  241. if (NT_SUCCESS( Status )) {
  242. NtFlushKey( Handle );
  243. NtClose( Handle );
  244. }
  245. p = RegistryContext->OpenHiveKeys;
  246. while (p) {
  247. RegCloseKey( p->KeyHandle );
  248. p1 = p;
  249. p = p->Next;
  250. HeapFree( GetProcessHeap(), 0, p1 );
  251. };
  252. do {
  253. Status = NtUnloadKey( &RegistryContext->HiveRootKey );
  254. }
  255. while (NT_SUCCESS( Status ) );
  256. NtClose( RegistryContext->HiveRootHandle );
  257. return;
  258. }
  259. void
  260. RegRememberOpenKey(
  261. IN PREG_CONTEXT RegistryContext,
  262. IN HKEY KeyHandle
  263. )
  264. {
  265. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  266. pp = &RegistryContext->OpenHiveKeys;
  267. while ((p = *pp) != NULL) {
  268. if (p->KeyHandle == KeyHandle) {
  269. p->ReferenceCount += 1;
  270. return;
  271. }
  272. else {
  273. pp = &p->Next;
  274. }
  275. }
  276. p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) );
  277. if (p != NULL) {
  278. p->KeyHandle = KeyHandle;
  279. p->ReferenceCount = 1;
  280. p->Next = NULL;
  281. *pp = p;
  282. }
  283. return;
  284. }
  285. void
  286. RegForgetOpenKey(
  287. IN PREG_CONTEXT RegistryContext,
  288. IN HKEY KeyHandle
  289. )
  290. {
  291. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  292. pp = &RegistryContext->OpenHiveKeys;
  293. while ((p = *pp) != NULL) {
  294. if (p->KeyHandle == KeyHandle) {
  295. p->ReferenceCount -= 1;
  296. if (p->ReferenceCount == 0) {
  297. *pp = p->Next;
  298. HeapFree( GetProcessHeap(), 0, p );
  299. return;
  300. }
  301. }
  302. else {
  303. pp = &p->Next;
  304. }
  305. }
  306. return;
  307. }
  308. BOOLEAN
  309. RegCheckPrefix(
  310. IN OUT PCWSTR *s,
  311. IN PCWSTR Prefix,
  312. IN ULONG PrefixLength
  313. )
  314. {
  315. if (PrefixLength == 0) {
  316. return FALSE;
  317. }
  318. if (!_wcsnicmp( *s, Prefix, PrefixLength )) {
  319. *s += PrefixLength;
  320. return TRUE;
  321. }
  322. return FALSE;
  323. }
  324. BOOLEAN
  325. RegValidateKeyPath(
  326. IN PREG_CONTEXT RegistryContext,
  327. IN OUT PHKEY RootKeyHandle,
  328. IN OUT PCWSTR *SubKeyName
  329. )
  330. {
  331. PCWSTR s;
  332. s = *SubKeyName;
  333. if (*RootKeyHandle == NULL) {
  334. if (RegCheckPrefix( &s, L"USER:", 5 ) ||
  335. RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 )
  336. ) {
  337. if (RegistryContext->CurrentUserRoot == NULL) {
  338. SetLastError( ERROR_BAD_PATHNAME );
  339. return FALSE;
  340. }
  341. if (*s == L'\\') {
  342. s += 1;
  343. }
  344. else
  345. if (s[-1] != L':' && *s != UNICODE_NULL) {
  346. SetLastError( ERROR_BAD_PATHNAME );
  347. return FALSE;
  348. }
  349. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  350. }
  351. else
  352. if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) {
  353. if (*s == L'\\') {
  354. s += 1;
  355. }
  356. else
  357. if (*s != UNICODE_NULL) {
  358. SetLastError( ERROR_BAD_PATHNAME );
  359. return FALSE;
  360. }
  361. *RootKeyHandle = RegistryContext->MachineRoot;
  362. }
  363. else
  364. if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) {
  365. if (*s == L'\\') {
  366. s += 1;
  367. }
  368. else
  369. if (*s != UNICODE_NULL) {
  370. SetLastError( ERROR_BAD_PATHNAME );
  371. return FALSE;
  372. }
  373. *RootKeyHandle = RegistryContext->UsersRoot;
  374. }
  375. else
  376. if (*s != L'\\') {
  377. SetLastError( ERROR_BAD_PATHNAME );
  378. return FALSE;
  379. }
  380. else
  381. if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) {
  382. *RootKeyHandle = RegistryContext->MachineRoot;
  383. if (*s == L'\\') {
  384. s += 1;
  385. }
  386. }
  387. else
  388. if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) {
  389. *RootKeyHandle = RegistryContext->UsersRoot;
  390. if (*s == L'\\') {
  391. s += 1;
  392. }
  393. }
  394. else
  395. if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) {
  396. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  397. if (*s == L'\\') {
  398. s += 1;
  399. }
  400. }
  401. else
  402. if (!_wcsicmp( *SubKeyName, L"\\Registry" )) {
  403. *RootKeyHandle = NULL;
  404. }
  405. else {
  406. SetLastError( ERROR_BAD_PATHNAME );
  407. return FALSE;
  408. }
  409. }
  410. else
  411. if (*s == L'\\') {
  412. SetLastError( ERROR_BAD_PATHNAME );
  413. return FALSE;
  414. }
  415. *SubKeyName = s;
  416. return TRUE;
  417. }
  418. LONG
  419. RTCreateKey(
  420. IN PREG_CONTEXT RegistryContext,
  421. IN HKEY RootKeyHandle,
  422. IN PCWSTR SubKeyName,
  423. IN ACCESS_MASK DesiredAccess,
  424. IN ULONG CreateOptions,
  425. IN PVOID SecurityDescriptor,
  426. OUT PHKEY ReturnedKeyHandle,
  427. OUT PULONG Disposition
  428. )
  429. {
  430. LONG Error;
  431. SECURITY_ATTRIBUTES SecurityAttributes;
  432. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  433. return GetLastError();
  434. }
  435. if (RootKeyHandle == NULL) {
  436. *Disposition = REG_OPENED_EXISTING_KEY;
  437. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  438. return NO_ERROR;
  439. }
  440. else
  441. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  442. *ReturnedKeyHandle = NULL;
  443. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  444. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  445. }
  446. else
  447. if (!_wcsicmp( SubKeyName, L"Users" )) {
  448. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  449. }
  450. if (*ReturnedKeyHandle != NULL) {
  451. return NO_ERROR;
  452. }
  453. else {
  454. return ERROR_PATH_NOT_FOUND;
  455. }
  456. }
  457. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  458. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  459. SecurityAttributes.bInheritHandle = FALSE;
  460. Error = RegCreateKeyEx( RootKeyHandle,
  461. SubKeyName,
  462. 0,
  463. NULL,
  464. CreateOptions,
  465. (REGSAM)DesiredAccess,
  466. &SecurityAttributes,
  467. ReturnedKeyHandle,
  468. Disposition
  469. );
  470. if (Error == NO_ERROR &&
  471. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  472. ) {
  473. RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
  474. }
  475. if (Error == NO_ERROR &&
  476. *Disposition == REG_OPENED_EXISTING_KEY &&
  477. SecurityDescriptor != NULL
  478. ) {
  479. RegSetKeySecurity( *ReturnedKeyHandle,
  480. DACL_SECURITY_INFORMATION,
  481. SecurityDescriptor
  482. );
  483. }
  484. return Error;
  485. }
  486. LONG
  487. RTOpenKey(
  488. IN PREG_CONTEXT RegistryContext,
  489. IN HKEY RootKeyHandle,
  490. IN PCWSTR SubKeyName,
  491. IN ACCESS_MASK DesiredAccess,
  492. IN ULONG OpenOptions,
  493. OUT PHKEY ReturnedKeyHandle
  494. )
  495. {
  496. LONG Error;
  497. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  498. return GetLastError();
  499. }
  500. if (RootKeyHandle == NULL) {
  501. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  502. return NO_ERROR;
  503. }
  504. else
  505. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  506. *ReturnedKeyHandle = NULL;
  507. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  508. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  509. }
  510. else
  511. if (!_wcsicmp( SubKeyName, L"Users" )) {
  512. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  513. }
  514. if (*ReturnedKeyHandle != NULL) {
  515. return NO_ERROR;
  516. }
  517. else {
  518. return ERROR_PATH_NOT_FOUND;
  519. }
  520. }
  521. Error = RegOpenKeyEx( RootKeyHandle,
  522. SubKeyName,
  523. OpenOptions,
  524. DesiredAccess,
  525. ReturnedKeyHandle
  526. );
  527. if (Error == NO_ERROR &&
  528. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  529. ) {
  530. RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
  531. }
  532. return Error;
  533. }
  534. LONG
  535. RTCloseKey(
  536. IN PREG_CONTEXT RegistryContext,
  537. IN HKEY KeyHandle
  538. )
  539. {
  540. LONG Error;
  541. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  542. return NO_ERROR;
  543. }
  544. else {
  545. Error = RegCloseKey( KeyHandle );
  546. if (Error == NO_ERROR &&
  547. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  548. ) {
  549. RegForgetOpenKey( RegistryContext, KeyHandle );
  550. }
  551. return Error;
  552. }
  553. }
  554. LONG
  555. RTEnumerateValueKey(
  556. IN PREG_CONTEXT RegistryContext,
  557. IN HKEY KeyHandle,
  558. IN ULONG Index,
  559. OUT PULONG ValueType,
  560. IN OUT PULONG ValueNameLength,
  561. OUT PWSTR ValueName,
  562. IN OUT PULONG ValueDataLength,
  563. OUT PVOID ValueData
  564. )
  565. {
  566. ULONG Error;
  567. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  568. return ERROR_NO_MORE_ITEMS;
  569. }
  570. else {
  571. Error = RegEnumValue( KeyHandle,
  572. Index,
  573. ValueName,
  574. ValueNameLength,
  575. NULL,
  576. ValueType,
  577. ValueData,
  578. ValueDataLength
  579. );
  580. if (Error == NO_ERROR) {
  581. RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
  582. }
  583. return Error;
  584. }
  585. }
  586. LONG
  587. RTQueryValueKey(
  588. IN PREG_CONTEXT RegistryContext,
  589. IN HKEY KeyHandle,
  590. IN PWSTR ValueName,
  591. OUT PULONG ValueType,
  592. IN OUT PULONG ValueDataLength,
  593. OUT PVOID ValueData
  594. )
  595. {
  596. LONG Error;
  597. Error = RegQueryValueEx( KeyHandle,
  598. ValueName,
  599. NULL,
  600. ValueType,
  601. ValueData,
  602. ValueDataLength
  603. );
  604. if (Error == NO_ERROR) {
  605. RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
  606. }
  607. return Error;
  608. }