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.

719 lines
20 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. //
  83. // This code comes from a library that can support remote machine name
  84. // for our use though we never support remote machine name, so that
  85. // bit of code is commented out.
  86. //
  87. UNREFERENCED_PARAMETER( MachineName );
  88. #if 0
  89. if (MachineName != NULL) {
  90. if (HiveRootName || HiveFileName ) {
  91. return ERROR_INVALID_PARAMETER;
  92. }
  93. Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot );
  94. if (Error == NO_ERROR) {
  95. Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot );
  96. if (Error == NO_ERROR) {
  97. Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot );
  98. }
  99. }
  100. if (Error != NO_ERROR) {
  101. if (RegistryContext->MachineRoot != NULL) {
  102. RegCloseKey( RegistryContext->MachineRoot );
  103. RegistryContext->MachineRoot = NULL;
  104. }
  105. if (RegistryContext->UsersRoot != NULL) {
  106. RegCloseKey( RegistryContext->UsersRoot );
  107. RegistryContext->UsersRoot = NULL;
  108. }
  109. return Error;
  110. }
  111. wcsncpy( RegistryContext->MachinePath, L"\\Registry\\Machine", MAX_PATH );
  112. RegistryContext->MachinePath[MAX_PATH-1] = L'\0';
  113. wcsncpy( RegistryContext->UsersPath, L"\\Registry\\Users", MAX_PATH );
  114. RegistryContext->UsersPath[MAX_PATH-1] = L'\0';
  115. wcsncpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default",MAX_PATH );
  116. RegistryContext->CurrentUserPath[MAX_PATH-1] = L'\0';
  117. RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY;
  118. } else
  119. #endif
  120. if (HiveRootName != NULL || HiveFileName != NULL) {
  121. // If they sent us one, they need to send us both.
  122. if (HiveRootName == NULL || HiveFileName == NULL ) {
  123. return ERROR_INVALID_PARAMETER;
  124. }
  125. if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) {
  126. return ERROR_PRIVILEGE_NOT_HELD;
  127. }
  128. RegistryContext->MachineRoot = NULL;
  129. RegistryContext->UsersRoot = NULL;
  130. RegistryContext->CurrentUserRoot = NULL;
  131. Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName );
  132. if (Error != NO_ERROR) {
  133. return Error;
  134. }
  135. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  136. *DefaultRootKeyName = HiveRootName;
  137. }
  138. RegistryContext->Target = REG_TARGET_HIVE_REGISTRY;
  139. } else {
  140. NTSTATUS Status;
  141. UNICODE_STRING CurrentUserKeyPath;
  142. RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
  143. RegistryContext->UsersRoot = HKEY_USERS;
  144. RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
  145. wcsncpy( RegistryContext->MachinePath, L"\\Registry\\Machine",MAX_PATH );
  146. RegistryContext->MachinePath[MAX_PATH-1] = L'\0';
  147. wcsncpy( RegistryContext->UsersPath, L"\\Registry\\Users",MAX_PATH );
  148. RegistryContext->UsersPath[MAX_PATH-1] = L'\0';
  149. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  150. if (!NT_SUCCESS( Status )) {
  151. SetLastError( RtlNtStatusToDosError( Status ) );
  152. return FALSE;
  153. }
  154. wcsncpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer, MAX_PATH );
  155. RegistryContext->CurrentUserPath[MAX_PATH-1] = L'\0';
  156. RtlFreeUnicodeString( &CurrentUserKeyPath );
  157. RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY;
  158. }
  159. if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
  160. *DefaultRootKeyName = L"\\Registry";
  161. }
  162. RegistryContext->MachinePathLength = (DWORD)wcslen( RegistryContext->MachinePath );
  163. RegistryContext->UsersPathLength = (DWORD)wcslen( RegistryContext->UsersPath );
  164. RegistryContext->CurrentUserPathLength = (DWORD)wcslen( RegistryContext->CurrentUserPath );
  165. return NO_ERROR;
  166. }
  167. LONG
  168. RTDisconnectFromRegistry(
  169. IN PREG_CONTEXT RegistryContext
  170. )
  171. {
  172. switch ( RegistryContext->Target ) {
  173. case REG_TARGET_DISCONNECTED:
  174. break;
  175. case REG_TARGET_LOCAL_REGISTRY:
  176. break;
  177. case REG_TARGET_REMOTE_REGISTRY:
  178. break;
  179. case REG_TARGET_HIVE_REGISTRY:
  180. RegUnloadHive( RegistryContext );
  181. break;
  182. }
  183. if (PrivilegeEnabled) {
  184. RTDisableBackupRestorePrivilege();
  185. }
  186. RegistryContext->Target = REG_TARGET_DISCONNECTED;
  187. return NO_ERROR;
  188. }
  189. UNICODE_STRING RegHiveRootName;
  190. LONG
  191. RegLoadHive(
  192. IN PREG_CONTEXT RegistryContext,
  193. IN PWSTR HiveFileName,
  194. IN PWSTR HiveRootName
  195. )
  196. {
  197. NTSTATUS Status;
  198. UNICODE_STRING NtFileName;
  199. OBJECT_ATTRIBUTES File;
  200. if (!RtlDosPathNameToNtPathName_U( HiveFileName,
  201. &NtFileName,
  202. NULL,
  203. NULL
  204. )
  205. ) {
  206. return ERROR_BAD_PATHNAME;
  207. }
  208. InitializeObjectAttributes( &File,
  209. &NtFileName,
  210. OBJ_CASE_INSENSITIVE,
  211. NULL,
  212. NULL
  213. );
  214. RtlInitUnicodeString( &RegHiveRootName, L"\\Registry");
  215. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  216. &RegHiveRootName,
  217. OBJ_CASE_INSENSITIVE,
  218. NULL,
  219. NULL
  220. );
  221. Status = NtOpenKey( &RegistryContext->HiveRootHandle,
  222. MAXIMUM_ALLOWED,
  223. &RegistryContext->HiveRootKey
  224. );
  225. RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
  226. if (!NT_SUCCESS(Status)) {
  227. return RtlNtStatusToDosError( Status );
  228. }
  229. RtlInitUnicodeString( &RegHiveRootName, HiveRootName );
  230. InitializeObjectAttributes( &RegistryContext->HiveRootKey,
  231. &RegHiveRootName,
  232. OBJ_CASE_INSENSITIVE,
  233. RegistryContext->HiveRootHandle,
  234. NULL
  235. );
  236. NtUnloadKey( &RegistryContext->HiveRootKey );
  237. Status = NtLoadKey( &RegistryContext->HiveRootKey, &File );
  238. if (!NT_SUCCESS( Status )) {
  239. return RtlNtStatusToDosError( Status );
  240. }
  241. return NO_ERROR;
  242. }
  243. void
  244. RegUnloadHive(
  245. IN PREG_CONTEXT RegistryContext
  246. )
  247. {
  248. NTSTATUS Status;
  249. HANDLE Handle;
  250. PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
  251. Status = NtOpenKey( &Handle,
  252. MAXIMUM_ALLOWED,
  253. &RegistryContext->HiveRootKey
  254. );
  255. if (NT_SUCCESS( Status )) {
  256. NtFlushKey( Handle );
  257. NtClose( Handle );
  258. }
  259. p = RegistryContext->OpenHiveKeys;
  260. while (p) {
  261. RegCloseKey( p->KeyHandle );
  262. p1 = p;
  263. p = p->Next;
  264. HeapFree( GetProcessHeap(), 0, p1 );
  265. };
  266. do {
  267. Status = NtUnloadKey( &RegistryContext->HiveRootKey );
  268. }
  269. while (NT_SUCCESS( Status ) );
  270. NtClose( RegistryContext->HiveRootHandle );
  271. return;
  272. }
  273. DWORD
  274. RegRememberOpenKey(
  275. IN PREG_CONTEXT RegistryContext,
  276. IN HKEY KeyHandle
  277. )
  278. {
  279. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  280. DWORD RetVal = ERROR_SUCCESS;
  281. pp = &RegistryContext->OpenHiveKeys;
  282. while ((p = *pp) != NULL) {
  283. if (p->KeyHandle == KeyHandle) {
  284. p->ReferenceCount += 1;
  285. RetVal = ERROR_SUCCESS;
  286. goto exit;
  287. } else {
  288. pp = &p->Next;
  289. }
  290. }
  291. p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) );
  292. if (p != NULL) {
  293. p->KeyHandle = KeyHandle;
  294. p->ReferenceCount = 1;
  295. p->Next = NULL;
  296. *pp = p;
  297. RetVal = ERROR_SUCCESS;
  298. } else {
  299. RetVal = ERROR_OUTOFMEMORY;
  300. }
  301. exit:
  302. return(RetVal);
  303. }
  304. void
  305. RegForgetOpenKey(
  306. IN PREG_CONTEXT RegistryContext,
  307. IN HKEY KeyHandle
  308. )
  309. {
  310. PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
  311. pp = &RegistryContext->OpenHiveKeys;
  312. while ((p = *pp) != NULL) {
  313. if (p->KeyHandle == KeyHandle) {
  314. p->ReferenceCount -= 1;
  315. if (p->ReferenceCount == 0) {
  316. *pp = p->Next;
  317. HeapFree( GetProcessHeap(), 0, p );
  318. return;
  319. }
  320. } else {
  321. pp = &p->Next;
  322. }
  323. }
  324. return;
  325. }
  326. BOOLEAN
  327. RegCheckPrefix(
  328. IN OUT PCWSTR *s,
  329. IN PCWSTR Prefix,
  330. IN ULONG PrefixLength
  331. )
  332. {
  333. if (PrefixLength == 0) {
  334. return FALSE;
  335. }
  336. if (!_wcsnicmp( *s, Prefix, PrefixLength )) {
  337. *s += PrefixLength;
  338. return TRUE;
  339. }
  340. return FALSE;
  341. }
  342. BOOLEAN
  343. RegValidateKeyPath(
  344. IN PREG_CONTEXT RegistryContext,
  345. IN OUT PHKEY RootKeyHandle,
  346. IN OUT PCWSTR *SubKeyName
  347. )
  348. {
  349. PCWSTR s;
  350. s = *SubKeyName;
  351. if (*RootKeyHandle == NULL) {
  352. if (RegCheckPrefix( &s, L"USER:", 5 ) ||
  353. RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 )
  354. ) {
  355. if (RegistryContext->CurrentUserRoot == NULL) {
  356. SetLastError( ERROR_BAD_PATHNAME );
  357. return FALSE;
  358. }
  359. if (*s == L'\\') {
  360. s += 1;
  361. } else
  362. if (s[-1] != L':' && *s != UNICODE_NULL) {
  363. SetLastError( ERROR_BAD_PATHNAME );
  364. return FALSE;
  365. }
  366. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  367. } else
  368. if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) {
  369. if (*s == L'\\') {
  370. s += 1;
  371. } else
  372. if (*s != UNICODE_NULL) {
  373. SetLastError( ERROR_BAD_PATHNAME );
  374. return FALSE;
  375. }
  376. *RootKeyHandle = RegistryContext->MachineRoot;
  377. } else
  378. if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) {
  379. if (*s == L'\\') {
  380. s += 1;
  381. } else
  382. if (*s != UNICODE_NULL) {
  383. SetLastError( ERROR_BAD_PATHNAME );
  384. return FALSE;
  385. }
  386. *RootKeyHandle = RegistryContext->UsersRoot;
  387. } else
  388. if (*s != L'\\') {
  389. SetLastError( ERROR_BAD_PATHNAME );
  390. return FALSE;
  391. } else
  392. if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) {
  393. *RootKeyHandle = RegistryContext->MachineRoot;
  394. if (*s == L'\\') {
  395. s += 1;
  396. }
  397. } else
  398. if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) {
  399. *RootKeyHandle = RegistryContext->UsersRoot;
  400. if (*s == L'\\') {
  401. s += 1;
  402. }
  403. } else
  404. if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) {
  405. *RootKeyHandle = RegistryContext->CurrentUserRoot;
  406. if (*s == L'\\') {
  407. s += 1;
  408. }
  409. } else
  410. if (!_wcsicmp( *SubKeyName, L"\\Registry" )) {
  411. *RootKeyHandle = NULL;
  412. } else {
  413. SetLastError( ERROR_BAD_PATHNAME );
  414. return FALSE;
  415. }
  416. } else
  417. if (*s == L'\\') {
  418. SetLastError( ERROR_BAD_PATHNAME );
  419. return FALSE;
  420. }
  421. *SubKeyName = s;
  422. return TRUE;
  423. }
  424. LONG
  425. RTCreateKey(
  426. IN PREG_CONTEXT RegistryContext,
  427. IN HKEY RootKeyHandle,
  428. IN PCWSTR SubKeyName,
  429. IN ACCESS_MASK DesiredAccess,
  430. IN ULONG CreateOptions,
  431. IN PVOID SecurityDescriptor,
  432. OUT PHKEY ReturnedKeyHandle,
  433. OUT PULONG Disposition
  434. )
  435. {
  436. LONG Error;
  437. SECURITY_ATTRIBUTES SecurityAttributes;
  438. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  439. return GetLastError();
  440. }
  441. if (RootKeyHandle == NULL) {
  442. *Disposition = REG_OPENED_EXISTING_KEY;
  443. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  444. return NO_ERROR;
  445. } else
  446. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  447. *ReturnedKeyHandle = NULL;
  448. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  449. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  450. } else
  451. if (!_wcsicmp( SubKeyName, L"Users" )) {
  452. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  453. }
  454. if (*ReturnedKeyHandle != NULL) {
  455. return NO_ERROR;
  456. } else {
  457. return ERROR_PATH_NOT_FOUND;
  458. }
  459. }
  460. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  461. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  462. SecurityAttributes.bInheritHandle = FALSE;
  463. Error = RegCreateKeyEx( RootKeyHandle,
  464. SubKeyName,
  465. 0,
  466. NULL,
  467. CreateOptions,
  468. (REGSAM)DesiredAccess,
  469. &SecurityAttributes,
  470. ReturnedKeyHandle,
  471. Disposition
  472. );
  473. if (Error == NO_ERROR &&
  474. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  475. ) {
  476. Error = RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
  477. }
  478. if (Error == NO_ERROR &&
  479. *Disposition == REG_OPENED_EXISTING_KEY &&
  480. SecurityDescriptor != NULL
  481. ) {
  482. RegSetKeySecurity( *ReturnedKeyHandle,
  483. DACL_SECURITY_INFORMATION,
  484. SecurityDescriptor
  485. );
  486. }
  487. return Error;
  488. }
  489. LONG
  490. RTOpenKey(
  491. IN PREG_CONTEXT RegistryContext,
  492. IN HKEY RootKeyHandle,
  493. IN PCWSTR SubKeyName,
  494. IN ACCESS_MASK DesiredAccess,
  495. IN ULONG OpenOptions,
  496. OUT PHKEY ReturnedKeyHandle
  497. )
  498. {
  499. LONG Error;
  500. if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
  501. return GetLastError();
  502. }
  503. if (RootKeyHandle == NULL) {
  504. *ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
  505. return NO_ERROR;
  506. } else
  507. if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
  508. *ReturnedKeyHandle = NULL;
  509. if (!_wcsicmp( SubKeyName, L"Machine" )) {
  510. *ReturnedKeyHandle = RegistryContext->MachineRoot;
  511. } else
  512. if (!_wcsicmp( SubKeyName, L"Users" )) {
  513. *ReturnedKeyHandle = RegistryContext->UsersRoot;
  514. }
  515. if (*ReturnedKeyHandle != NULL) {
  516. return NO_ERROR;
  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. } else {
  544. Error = RegCloseKey( KeyHandle );
  545. if (Error == NO_ERROR &&
  546. RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
  547. ) {
  548. RegForgetOpenKey( RegistryContext, KeyHandle );
  549. }
  550. return Error;
  551. }
  552. }
  553. LONG
  554. RTEnumerateValueKey(
  555. IN PREG_CONTEXT RegistryContext,
  556. IN HKEY KeyHandle,
  557. IN ULONG Index,
  558. OUT PULONG ValueType,
  559. IN OUT PULONG ValueNameLength,
  560. OUT PWSTR ValueName,
  561. IN OUT PULONG ValueDataLength,
  562. OUT PVOID ValueData
  563. )
  564. {
  565. ULONG Error;
  566. UNREFERENCED_PARAMETER(RegistryContext);
  567. if (KeyHandle == HKEY_REGISTRY_ROOT) {
  568. return ERROR_NO_MORE_ITEMS;
  569. } else {
  570. Error = RegEnumValue( KeyHandle,
  571. Index,
  572. ValueName,
  573. ValueNameLength,
  574. NULL,
  575. ValueType,
  576. ValueData,
  577. ValueDataLength
  578. );
  579. if (Error == NO_ERROR) {
  580. RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
  581. }
  582. return Error;
  583. }
  584. }
  585. LONG
  586. RTQueryValueKey(
  587. IN PREG_CONTEXT RegistryContext,
  588. IN HKEY KeyHandle,
  589. IN PWSTR ValueName,
  590. OUT PULONG ValueType,
  591. IN OUT PULONG ValueDataLength,
  592. OUT PVOID ValueData
  593. )
  594. {
  595. LONG Error;
  596. UNREFERENCED_PARAMETER(RegistryContext);
  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. }