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.

670 lines
18 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_U 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) || (lpFile->Length & 1)) {
  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 = RtlDosPathNameToRelativeNtPathName_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 RtlDosPathNameToRelativeNtPathName_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 = 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 RtlDosPathNameToRelativeNtPathName_U.
  139. //
  140. RtlReleaseRelativeName(&RelativeName);
  141. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  142. //
  143. // Check the results of the NtOpenFile.
  144. //
  145. if( NT_SUCCESS( NtStatus )) {
  146. #ifdef LOCAL
  147. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  148. HKEY hkRestoreKey;
  149. UNICODE_STRING EmptyString = {0, 0, NULL};
  150. //
  151. // We need to restore to to user if it exists,
  152. // machine if not
  153. //
  154. NtStatus = BaseRegOpenClassKey(
  155. hKey,
  156. &EmptyString,
  157. 0,
  158. MAXIMUM_ALLOWED,
  159. &hkRestoreKey);
  160. if (NT_SUCCESS(NtStatus)) {
  161. //
  162. // Now restore to the highest precedence key
  163. //
  164. NtStatus = NtRestoreKey( hkRestoreKey, Handle, dwFlags );
  165. NtClose(hkRestoreKey);
  166. }
  167. } else {
  168. //
  169. // If this isn't in hkcr, then just restore to the supplied object
  170. //
  171. NtStatus = NtRestoreKey( hKey, Handle, dwFlags );
  172. }
  173. #else // LOCAL
  174. //
  175. // Now call the NT API
  176. //
  177. NtStatus = NtRestoreKey( hKey, Handle, dwFlags );
  178. #endif // LOCAL
  179. //
  180. // Close the file.
  181. //
  182. NtStatus1 = NtClose(Handle);
  183. ASSERT( NT_SUCCESS( NtStatus1 ));
  184. }
  185. RPC_REVERT_TO_SELF();
  186. #ifdef LOCAL
  187. if (NT_SUCCESS(NtStatus) && !(dwFlags & REG_WHOLE_HIVE_VOLATILE) && gpfnTermsrvRestoreKey) {
  188. gpfnTermsrvRestoreKey(hKey, Handle, dwFlags);
  189. }
  190. #endif
  191. //
  192. // Map the result of NtRestoreKey and return.
  193. //
  194. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  195. }
  196. error_status_t
  197. BaseRegSaveKey(
  198. IN HKEY hKey,
  199. IN PUNICODE_STRING lpFile,
  200. IN PRPC_SECURITY_ATTRIBUTES pRpcSecurityAttributes OPTIONAL
  201. )
  202. /*++
  203. Routine Description:
  204. Saves the given key to the specified file.
  205. Arguments:
  206. hKey - Supplies a handle to the open key.
  207. lpFile - Supplies the name of the file to save the key to.
  208. pRpcSecurityAttributes - Supplies the security attributes of
  209. the file.
  210. Return Value:
  211. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  212. --*/
  213. {
  214. BOOLEAN ErrorFlag;
  215. UNICODE_STRING FileName;
  216. RTL_RELATIVE_NAME_U RelativeName;
  217. OBJECT_ATTRIBUTES Obja;
  218. IO_STATUS_BLOCK IoStatusBlock;
  219. PVOID FreeBuffer;
  220. NTSTATUS NtStatus;
  221. NTSTATUS NtStatus1;
  222. HANDLE Handle;
  223. ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
  224. if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) || (lpFile->Length & 1) ) {
  225. return ERROR_INVALID_PARAMETER;
  226. }
  227. RPC_IMPERSONATE_CLIENT( NULL );
  228. //
  229. // Remove the NULL from the Length. This was added by the client
  230. // so that RPC would transmit the entire thing.
  231. //
  232. if ( lpFile->Length > 0 ) {
  233. lpFile->Length -= sizeof( UNICODE_NULL );
  234. }
  235. if ( ARGUMENT_PRESENT( pRpcSecurityAttributes ) ) {
  236. if( (pRpcSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor == NULL) ||
  237. (!RtlValidRelativeSecurityDescriptor( pRpcSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor,
  238. pRpcSecurityAttributes->RpcSecurityDescriptor.cbInSecurityDescriptor,
  239. 0)) ) {
  240. RPC_REVERT_TO_SELF();
  241. return ERROR_INVALID_PARAMETER;
  242. }
  243. }
  244. //
  245. // Convert the DOS path name to a canonical Nt path name.
  246. //
  247. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
  248. lpFile->Buffer,
  249. &FileName,
  250. NULL,
  251. &RelativeName
  252. );
  253. //
  254. // If the name was not succesfully converted assume it was invalid.
  255. //
  256. if( ! ErrorFlag ) {
  257. RPC_REVERT_TO_SELF();
  258. return ERROR_INVALID_PARAMETER;
  259. }
  260. //
  261. // Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  262. //
  263. FreeBuffer = FileName.Buffer;
  264. //
  265. // If a relative name and directory handle will work, use those.
  266. //
  267. if ( RelativeName.RelativeName.Length ) {
  268. //
  269. // Replace the full path with the relative path.
  270. //
  271. FileName = RelativeName.RelativeName;
  272. } else {
  273. //
  274. // Using the full path - no containing directory.
  275. //
  276. RelativeName.ContainingDirectory = NULL;
  277. }
  278. //
  279. // Initialize the Obja structure for the save file.
  280. //
  281. InitializeObjectAttributes(
  282. &Obja,
  283. &FileName,
  284. OBJ_CASE_INSENSITIVE,
  285. RelativeName.ContainingDirectory,
  286. ARGUMENT_PRESENT( pRpcSecurityAttributes )
  287. ? pRpcSecurityAttributes
  288. ->RpcSecurityDescriptor.lpSecurityDescriptor
  289. : NULL
  290. );
  291. //
  292. // Create the file - fail if the file exists.
  293. //
  294. NtStatus = NtCreateFile(
  295. &Handle,
  296. GENERIC_WRITE | SYNCHRONIZE,
  297. &Obja,
  298. &IoStatusBlock,
  299. NULL,
  300. FILE_ATTRIBUTE_NORMAL,
  301. FILE_SHARE_READ,
  302. FILE_CREATE,
  303. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  304. NULL,
  305. 0
  306. );
  307. //
  308. // Free the buffer allocated by RtlDosPathNameToRelativeNtPathName_U.
  309. //
  310. RtlReleaseRelativeName(&RelativeName);
  311. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  312. //
  313. // Check the results of the NtCreateFile.
  314. //
  315. if ( NT_SUCCESS( NtStatus )) {
  316. #ifdef LOCAL
  317. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  318. HKEY hkMachineClass;
  319. HKEY hkUserClass;
  320. NtStatus = BaseRegGetUserAndMachineClass(
  321. NULL,
  322. hKey,
  323. MAXIMUM_ALLOWED,
  324. &hkMachineClass,
  325. &hkUserClass);
  326. if (NT_SUCCESS(NtStatus)) {
  327. //
  328. // We only need to merge keys if we have
  329. // more than one key
  330. //
  331. if (hkMachineClass && hkUserClass) {
  332. NtStatus = NtSaveMergedKeys(
  333. hkUserClass,
  334. hkMachineClass,
  335. Handle);
  336. //
  337. // Clean up the extra handle we opened
  338. //
  339. if (hkUserClass != hKey) {
  340. NtClose(hkUserClass);
  341. } else {
  342. NtClose(hkMachineClass);
  343. }
  344. } else {
  345. //
  346. // If there's only one key, use the regular
  347. // api
  348. //
  349. NtStatus = NtSaveKey( hKey, Handle );
  350. }
  351. }
  352. } else {
  353. //
  354. // If this isn't in hkcr, just save the regular way
  355. //
  356. NtStatus = NtSaveKey( hKey, Handle );
  357. }
  358. #else // LOCAL
  359. NtStatus = NtSaveKey( hKey, Handle );
  360. #endif // LOCAL
  361. //
  362. // Close the file.
  363. //
  364. NtStatus1 = NtClose( Handle );
  365. ASSERT( NT_SUCCESS( NtStatus1 ));
  366. }
  367. RPC_REVERT_TO_SELF();
  368. //
  369. // Map the result of NtSaveKey and return.
  370. //
  371. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  372. }
  373. error_status_t
  374. BaseRegSaveKeyEx(
  375. IN HKEY hKey,
  376. IN PUNICODE_STRING lpFile,
  377. IN PRPC_SECURITY_ATTRIBUTES pRpcSecurityAttributes OPTIONAL,
  378. IN DWORD Flags
  379. )
  380. /*++
  381. Routine Description:
  382. Saves the given key to the specified file.
  383. Arguments:
  384. hKey - Supplies a handle to the open key.
  385. lpFile - Supplies the name of the file to save the key to.
  386. pRpcSecurityAttributes - Supplies the security attributes of
  387. the file.
  388. Flags - Specifies the format the target registry hive will
  389. be saved on.
  390. Return Value:
  391. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  392. --*/
  393. {
  394. BOOLEAN ErrorFlag;
  395. UNICODE_STRING FileName;
  396. RTL_RELATIVE_NAME_U RelativeName;
  397. OBJECT_ATTRIBUTES Obja;
  398. IO_STATUS_BLOCK IoStatusBlock;
  399. PVOID FreeBuffer;
  400. NTSTATUS NtStatus;
  401. NTSTATUS NtStatus1;
  402. HANDLE Handle;
  403. ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
  404. if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) || (lpFile->Length & 1) ) {
  405. return ERROR_INVALID_PARAMETER;
  406. }
  407. RPC_IMPERSONATE_CLIENT( NULL );
  408. //
  409. // Remove the NULL from the Length. This was added by the client
  410. // so that RPC would transmit the entire thing.
  411. //
  412. if ( lpFile->Length > 0 ) {
  413. lpFile->Length -= sizeof( UNICODE_NULL );
  414. }
  415. if ( ARGUMENT_PRESENT( pRpcSecurityAttributes ) ) {
  416. if( (pRpcSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor == NULL) ||
  417. (!RtlValidRelativeSecurityDescriptor( pRpcSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor,
  418. pRpcSecurityAttributes->RpcSecurityDescriptor.cbInSecurityDescriptor,
  419. 0)) ) {
  420. RPC_REVERT_TO_SELF();
  421. return ERROR_INVALID_PARAMETER;
  422. }
  423. }
  424. //
  425. // Convert the DOS path name to a canonical Nt path name.
  426. //
  427. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
  428. lpFile->Buffer,
  429. &FileName,
  430. NULL,
  431. &RelativeName
  432. );
  433. //
  434. // If the name was not succesfully converted assume it was invalid.
  435. //
  436. if( ! ErrorFlag ) {
  437. RPC_REVERT_TO_SELF();
  438. return ERROR_INVALID_PARAMETER;
  439. }
  440. //
  441. // Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  442. //
  443. FreeBuffer = FileName.Buffer;
  444. //
  445. // If a relative name and directory handle will work, use those.
  446. //
  447. if ( RelativeName.RelativeName.Length ) {
  448. //
  449. // Replace the full path with the relative path.
  450. //
  451. FileName = RelativeName.RelativeName;
  452. } else {
  453. //
  454. // Using the full path - no containing directory.
  455. //
  456. RelativeName.ContainingDirectory = NULL;
  457. }
  458. //
  459. // Initialize the Obja structure for the save file.
  460. //
  461. InitializeObjectAttributes(
  462. &Obja,
  463. &FileName,
  464. OBJ_CASE_INSENSITIVE,
  465. RelativeName.ContainingDirectory,
  466. ARGUMENT_PRESENT( pRpcSecurityAttributes )
  467. ? pRpcSecurityAttributes
  468. ->RpcSecurityDescriptor.lpSecurityDescriptor
  469. : NULL
  470. );
  471. //
  472. // Create the file - fail if the file exists.
  473. //
  474. NtStatus = NtCreateFile(
  475. &Handle,
  476. GENERIC_WRITE | SYNCHRONIZE,
  477. &Obja,
  478. &IoStatusBlock,
  479. NULL,
  480. FILE_ATTRIBUTE_NORMAL,
  481. FILE_SHARE_READ,
  482. FILE_CREATE,
  483. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  484. NULL,
  485. 0
  486. );
  487. //
  488. // Free the buffer allocated by RtlDosPathNameToRelativeNtPathName_U.
  489. //
  490. RtlReleaseRelativeName(&RelativeName);
  491. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  492. //
  493. // Check the results of the NtCreateFile.
  494. //
  495. if ( NT_SUCCESS( NtStatus )) {
  496. #ifdef LOCAL
  497. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  498. //
  499. // not supported on merged hives just yet
  500. //
  501. NtStatus = STATUS_INVALID_PARAMETER;
  502. } else {
  503. //
  504. // If this isn't in hkcr, just save the regular way
  505. //
  506. NtStatus = NtSaveKeyEx( hKey, Handle, Flags );
  507. }
  508. #else // LOCAL
  509. NtStatus = NtSaveKeyEx( hKey, Handle, Flags );
  510. #endif // LOCAL
  511. //
  512. // Close the file.
  513. //
  514. NtStatus1 = NtClose( Handle );
  515. ASSERT( NT_SUCCESS( NtStatus1 ));
  516. }
  517. RPC_REVERT_TO_SELF();
  518. //
  519. // Map the result of NtSaveKey and return.
  520. //
  521. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  522. }