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.

650 lines
16 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Regsrkey.c
  5. Abstract:
  6. This module contains the save\restore key APIs, that is:
  7. - RegRestoreKeyW
  8. - RegSaveKeyW
  9. Author:
  10. David J. Gilman (davegi) 23-Jan-1992
  11. Notes:
  12. Revision History:
  13. 25-Mar-1992 Ramon J. San Andres (ramonsa)
  14. Changed to use RPC.
  15. --*/
  16. #include <rpc.h>
  17. #include "regrpc.h"
  18. #include "localreg.h"
  19. #ifdef LOCAL
  20. #include "tsappcmp.h"
  21. #include "regclass.h"
  22. #endif
  23. error_status_t
  24. BaseRegRestoreKey(
  25. IN HKEY hKey,
  26. IN PUNICODE_STRING lpFile,
  27. IN DWORD dwFlags
  28. )
  29. /*++
  30. Routine Description:
  31. Restore the tree in the supplied file onto the key referenced by the
  32. supplied key handle. The restored tree will overwrite all of the
  33. contents of the supplied hKey except for its name. Pictorially, if
  34. the file contains:
  35. A
  36. / \
  37. / \
  38. B C
  39. and the supplied key refers to a key name X, the resultant tree would
  40. look like:
  41. X
  42. / \
  43. / \
  44. B C
  45. Arguments:
  46. hKey - Supplies a handle to the key where the file is to be restored.
  47. lpFile - Supplies a pointer to an existing file name whose contents was
  48. created with RegSaveKey.
  49. dwFlags - Supplies an optional flag argument which can be:
  50. - REG_WHOLE_HIVE_VOLATILE
  51. If specified this flag causes a new, volatile
  52. (i.e. memory only) hive to be created. In this case
  53. the hKey can only refer to a child of HKEY_USERS or
  54. HKEY_LOCAL_MACHINE.
  55. If not specified, hKey can refer to any key in the
  56. Registry.
  57. Return Value:
  58. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  59. --*/
  60. {
  61. UNICODE_STRING FileName;
  62. RTL_RELATIVE_NAME RelativeName;
  63. OBJECT_ATTRIBUTES Obja;
  64. IO_STATUS_BLOCK IoStatusBlock;
  65. PVOID FreeBuffer;
  66. BOOLEAN ErrorFlag;
  67. NTSTATUS NtStatus;
  68. NTSTATUS NtStatus1;
  69. HANDLE Handle;
  70. ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
  71. if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) ) {
  72. return ERROR_INVALID_PARAMETER;
  73. }
  74. RPC_IMPERSONATE_CLIENT( NULL );
  75. //
  76. // Remove the NULL from the Length. This was added by the client
  77. // so that RPC would transmit the entire thing.
  78. //
  79. if ( lpFile->Length > 0 ) {
  80. lpFile->Length -= sizeof( UNICODE_NULL );
  81. }
  82. //
  83. // Convert the DOS path name to a canonical Nt path name.
  84. //
  85. ErrorFlag = RtlDosPathNameToNtPathName_U(
  86. lpFile->Buffer,
  87. &FileName,
  88. NULL,
  89. &RelativeName
  90. );
  91. //
  92. // If the name was not succesfully converted assume it was invalid.
  93. //
  94. if ( !ErrorFlag ) {
  95. RPC_REVERT_TO_SELF();
  96. return ERROR_INVALID_PARAMETER;
  97. }
  98. //
  99. // Remember the buffer allocated by RtlDosPathNameToNtPathName_U.
  100. //
  101. FreeBuffer = FileName.Buffer;
  102. //
  103. // If a relative name and directory handle will work, use those.
  104. //
  105. if ( RelativeName.RelativeName.Length ) {
  106. //
  107. // Replace the full path with the relative path.
  108. //
  109. FileName = *( PUNICODE_STRING ) &RelativeName.RelativeName;
  110. } else {
  111. //
  112. // Using the full path - no containing directory.
  113. //
  114. RelativeName.ContainingDirectory = NULL;
  115. }
  116. //
  117. // Initialize the Obja structure for the save file.
  118. //
  119. InitializeObjectAttributes(
  120. &Obja,
  121. &FileName,
  122. OBJ_CASE_INSENSITIVE,
  123. RelativeName.ContainingDirectory,
  124. NULL
  125. );
  126. //
  127. // Open the existing file.
  128. //
  129. NtStatus = NtOpenFile(
  130. &Handle,
  131. GENERIC_READ | SYNCHRONIZE,
  132. &Obja,
  133. &IoStatusBlock,
  134. FILE_SHARE_READ,
  135. FILE_SYNCHRONOUS_IO_NONALERT
  136. );
  137. //
  138. // Free the buffer allocated by RtlDosPathNameToNtPathName_U.
  139. //
  140. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  141. //
  142. // Check the results of the NtOpenFile.
  143. //
  144. if( NT_SUCCESS( NtStatus )) {
  145. #ifdef LOCAL
  146. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  147. HKEY hkRestoreKey;
  148. UNICODE_STRING EmptyString = {0, 0, NULL};
  149. //
  150. // We need to restore to to user if it exists,
  151. // machine if not
  152. //
  153. NtStatus = BaseRegOpenClassKey(
  154. hKey,
  155. &EmptyString,
  156. 0,
  157. MAXIMUM_ALLOWED,
  158. &hkRestoreKey);
  159. if (NT_SUCCESS(NtStatus)) {
  160. //
  161. // Now restore to the highest precedence key
  162. //
  163. NtStatus = NtRestoreKey( hkRestoreKey, Handle, dwFlags );
  164. NtClose(hkRestoreKey);
  165. }
  166. } else {
  167. //
  168. // If this isn't in hkcr, then just restore to the supplied object
  169. //
  170. NtStatus = NtRestoreKey( hKey, Handle, dwFlags );
  171. }
  172. #else // LOCAL
  173. //
  174. // Now call the NT API
  175. //
  176. NtStatus = NtRestoreKey( hKey, Handle, dwFlags );
  177. #endif // LOCAL
  178. //
  179. // Close the file.
  180. //
  181. NtStatus1 = NtClose(Handle);
  182. ASSERT( NT_SUCCESS( NtStatus1 ));
  183. }
  184. RPC_REVERT_TO_SELF();
  185. #ifdef LOCAL
  186. if (NT_SUCCESS(NtStatus) && !(dwFlags & REG_WHOLE_HIVE_VOLATILE) && gpfnTermsrvRestoreKey) {
  187. gpfnTermsrvRestoreKey(hKey, Handle, dwFlags);
  188. }
  189. #endif
  190. //
  191. // Map the result of NtRestoreKey and return.
  192. //
  193. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  194. }
  195. error_status_t
  196. BaseRegSaveKey(
  197. IN HKEY hKey,
  198. IN PUNICODE_STRING lpFile,
  199. IN PRPC_SECURITY_ATTRIBUTES pRpcSecurityAttributes OPTIONAL
  200. )
  201. /*++
  202. Routine Description:
  203. Saves the given key to the specified file.
  204. Arguments:
  205. hKey - Supplies a handle to the open key.
  206. lpFile - Supplies the name of the file to save the key to.
  207. pRpcSecurityAttributes - Supplies the security attributes of
  208. the file.
  209. Return Value:
  210. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  211. --*/
  212. {
  213. BOOLEAN ErrorFlag;
  214. UNICODE_STRING FileName;
  215. RTL_RELATIVE_NAME RelativeName;
  216. OBJECT_ATTRIBUTES Obja;
  217. IO_STATUS_BLOCK IoStatusBlock;
  218. PVOID FreeBuffer;
  219. NTSTATUS NtStatus;
  220. NTSTATUS NtStatus1;
  221. HANDLE Handle;
  222. ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
  223. if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) ) {
  224. return ERROR_INVALID_PARAMETER;
  225. }
  226. RPC_IMPERSONATE_CLIENT( NULL );
  227. //
  228. // Remove the NULL from the Length. This was added by the client
  229. // so that RPC would transmit the entire thing.
  230. //
  231. if ( lpFile->Length > 0 ) {
  232. lpFile->Length -= sizeof( UNICODE_NULL );
  233. }
  234. //
  235. // Convert the DOS path name to a canonical Nt path name.
  236. //
  237. ErrorFlag = RtlDosPathNameToNtPathName_U(
  238. lpFile->Buffer,
  239. &FileName,
  240. NULL,
  241. &RelativeName
  242. );
  243. //
  244. // If the name was not succesfully converted assume it was invalid.
  245. //
  246. if( ! ErrorFlag ) {
  247. RPC_REVERT_TO_SELF();
  248. return ERROR_INVALID_PARAMETER;
  249. }
  250. //
  251. // Remember the buffer allocatted by RtlDosPathNameToNtPathName_U.
  252. //
  253. FreeBuffer = FileName.Buffer;
  254. //
  255. // If a relative name and directory handle will work, use those.
  256. //
  257. if ( RelativeName.RelativeName.Length ) {
  258. //
  259. // Replace the full path with the relative path.
  260. //
  261. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  262. } else {
  263. //
  264. // Using the full path - no containing directory.
  265. //
  266. RelativeName.ContainingDirectory = NULL;
  267. }
  268. //
  269. // Initialize the Obja structure for the save file.
  270. //
  271. InitializeObjectAttributes(
  272. &Obja,
  273. &FileName,
  274. OBJ_CASE_INSENSITIVE,
  275. RelativeName.ContainingDirectory,
  276. ARGUMENT_PRESENT( pRpcSecurityAttributes )
  277. ? pRpcSecurityAttributes
  278. ->RpcSecurityDescriptor.lpSecurityDescriptor
  279. : NULL
  280. );
  281. //
  282. // Create the file - fail if the file exists.
  283. //
  284. NtStatus = NtCreateFile(
  285. &Handle,
  286. GENERIC_WRITE | SYNCHRONIZE,
  287. &Obja,
  288. &IoStatusBlock,
  289. NULL,
  290. FILE_ATTRIBUTE_NORMAL,
  291. FILE_SHARE_READ,
  292. FILE_CREATE,
  293. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  294. NULL,
  295. 0
  296. );
  297. //
  298. // Free the buffer allocated by RtlDosPathNameToNtPathName_U.
  299. //
  300. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  301. //
  302. // Check the results of the NtCreateFile.
  303. //
  304. if ( NT_SUCCESS( NtStatus )) {
  305. #ifdef LOCAL
  306. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  307. HKEY hkMachineClass;
  308. HKEY hkUserClass;
  309. NtStatus = BaseRegGetUserAndMachineClass(
  310. NULL,
  311. hKey,
  312. MAXIMUM_ALLOWED,
  313. &hkMachineClass,
  314. &hkUserClass);
  315. if (NT_SUCCESS(NtStatus)) {
  316. //
  317. // We only need to merge keys if we have
  318. // more than one key
  319. //
  320. if (hkMachineClass && hkUserClass) {
  321. NtStatus = NtSaveMergedKeys(
  322. hkUserClass,
  323. hkMachineClass,
  324. Handle);
  325. //
  326. // Clean up the extra handle we opened
  327. //
  328. if (hkUserClass != hKey) {
  329. NtClose(hkUserClass);
  330. } else {
  331. NtClose(hkMachineClass);
  332. }
  333. } else {
  334. //
  335. // If there's only one key, use the regular
  336. // api
  337. //
  338. NtStatus = NtSaveKey( hKey, Handle );
  339. }
  340. }
  341. } else {
  342. //
  343. // If this isn't in hkcr, just save the regular way
  344. //
  345. NtStatus = NtSaveKey( hKey, Handle );
  346. }
  347. #else // LOCAL
  348. NtStatus = NtSaveKey( hKey, Handle );
  349. #endif // LOCAL
  350. //
  351. // Close the file.
  352. //
  353. NtStatus1 = NtClose( Handle );
  354. ASSERT( NT_SUCCESS( NtStatus1 ));
  355. }
  356. RPC_REVERT_TO_SELF();
  357. //
  358. // Map the result of NtSaveKey and return.
  359. //
  360. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  361. }
  362. error_status_t
  363. BaseRegSaveKeyEx(
  364. IN HKEY hKey,
  365. IN PUNICODE_STRING lpFile,
  366. IN PRPC_SECURITY_ATTRIBUTES pRpcSecurityAttributes OPTIONAL,
  367. IN DWORD Flags
  368. )
  369. /*++
  370. Routine Description:
  371. Saves the given key to the specified file.
  372. Arguments:
  373. hKey - Supplies a handle to the open key.
  374. lpFile - Supplies the name of the file to save the key to.
  375. pRpcSecurityAttributes - Supplies the security attributes of
  376. the file.
  377. Flags - Specifies the format the target registry hive will
  378. be saved on.
  379. Return Value:
  380. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  381. --*/
  382. {
  383. BOOLEAN ErrorFlag;
  384. UNICODE_STRING FileName;
  385. RTL_RELATIVE_NAME RelativeName;
  386. OBJECT_ATTRIBUTES Obja;
  387. IO_STATUS_BLOCK IoStatusBlock;
  388. PVOID FreeBuffer;
  389. NTSTATUS NtStatus;
  390. NTSTATUS NtStatus1;
  391. HANDLE Handle;
  392. ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
  393. if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) ) {
  394. return ERROR_INVALID_PARAMETER;
  395. }
  396. RPC_IMPERSONATE_CLIENT( NULL );
  397. //
  398. // Remove the NULL from the Length. This was added by the client
  399. // so that RPC would transmit the entire thing.
  400. //
  401. if ( lpFile->Length > 0 ) {
  402. lpFile->Length -= sizeof( UNICODE_NULL );
  403. }
  404. //
  405. // Convert the DOS path name to a canonical Nt path name.
  406. //
  407. ErrorFlag = RtlDosPathNameToNtPathName_U(
  408. lpFile->Buffer,
  409. &FileName,
  410. NULL,
  411. &RelativeName
  412. );
  413. //
  414. // If the name was not succesfully converted assume it was invalid.
  415. //
  416. if( ! ErrorFlag ) {
  417. RPC_REVERT_TO_SELF();
  418. return ERROR_INVALID_PARAMETER;
  419. }
  420. //
  421. // Remember the buffer allocatted by RtlDosPathNameToNtPathName_U.
  422. //
  423. FreeBuffer = FileName.Buffer;
  424. //
  425. // If a relative name and directory handle will work, use those.
  426. //
  427. if ( RelativeName.RelativeName.Length ) {
  428. //
  429. // Replace the full path with the relative path.
  430. //
  431. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  432. } else {
  433. //
  434. // Using the full path - no containing directory.
  435. //
  436. RelativeName.ContainingDirectory = NULL;
  437. }
  438. //
  439. // Initialize the Obja structure for the save file.
  440. //
  441. InitializeObjectAttributes(
  442. &Obja,
  443. &FileName,
  444. OBJ_CASE_INSENSITIVE,
  445. RelativeName.ContainingDirectory,
  446. ARGUMENT_PRESENT( pRpcSecurityAttributes )
  447. ? pRpcSecurityAttributes
  448. ->RpcSecurityDescriptor.lpSecurityDescriptor
  449. : NULL
  450. );
  451. //
  452. // Create the file - fail if the file exists.
  453. //
  454. NtStatus = NtCreateFile(
  455. &Handle,
  456. GENERIC_WRITE | SYNCHRONIZE,
  457. &Obja,
  458. &IoStatusBlock,
  459. NULL,
  460. FILE_ATTRIBUTE_NORMAL,
  461. FILE_SHARE_READ,
  462. FILE_CREATE,
  463. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  464. NULL,
  465. 0
  466. );
  467. //
  468. // Free the buffer allocated by RtlDosPathNameToNtPathName_U.
  469. //
  470. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  471. //
  472. // Check the results of the NtCreateFile.
  473. //
  474. if ( NT_SUCCESS( NtStatus )) {
  475. #ifdef LOCAL
  476. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  477. //
  478. // not supported on merged hives just yet
  479. //
  480. NtStatus = STATUS_INVALID_PARAMETER;
  481. } else {
  482. //
  483. // If this isn't in hkcr, just save the regular way
  484. //
  485. NtStatus = NtSaveKeyEx( hKey, Handle, Flags );
  486. }
  487. #else // LOCAL
  488. NtStatus = NtSaveKeyEx( hKey, Handle, Flags );
  489. #endif // LOCAL
  490. //
  491. // Close the file.
  492. //
  493. NtStatus1 = NtClose( Handle );
  494. ASSERT( NT_SUCCESS( NtStatus1 ));
  495. }
  496. RPC_REVERT_TO_SELF();
  497. //
  498. // Map the result of NtSaveKey and return.
  499. //
  500. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  501. }