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.

564 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Reglukey.c
  5. Abstract:
  6. This module contains the server side Win32 Registry
  7. APIs to load, unload and replace keys. That is:
  8. - BaseRegLoadKeyA
  9. - BaseRegLoadKeyW
  10. - BaseRegUnLoadKeyA
  11. - BaseRegUnLoadKeyW
  12. - BaseRegReplaceKeyA
  13. - BaseRegReplaceKeyW
  14. Author:
  15. Ramon J. San Andres (ramonsa) 16-Apr-1992
  16. --*/
  17. #include <rpc.h>
  18. #include "regrpc.h"
  19. #include "localreg.h"
  20. error_status_t
  21. BaseRegLoadKey(
  22. IN HKEY hKey,
  23. IN PUNICODE_STRING lpSubKey OPTIONAL,
  24. IN PUNICODE_STRING lpFile
  25. )
  26. /*++
  27. Routine Description:
  28. Load the tree in the supplied file into the key referenced by the
  29. supplied key handle and sub-key. The loaded tree will overwrite all
  30. of the contents of the supplied sub-key except for its name.
  31. Pictorially, if the file contains:
  32. A
  33. / \
  34. / \
  35. B C
  36. and the supplied key refers to a key name X, the resultant tree would
  37. look like:
  38. X
  39. / \
  40. / \
  41. B C
  42. Arguments:
  43. hKey - Supplies the predefined handle HKEY_USERS or HKEY_LOCAL_MACHINE.
  44. lpSubKey is relative to this handle.
  45. lpSubKey - Supplies a path name to a new (i.e. non-existant) key
  46. where the supplied file will be loaded.
  47. lpFile - Supplies a pointer to an existing file name whose contents was
  48. created with RegSaveKey. The file name may not have an extension.
  49. Return Value:
  50. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  51. Notes:
  52. The difference between RegRestoreKey and RegLoadKey is that in the
  53. latter case the supplied file is used as the actual backing store
  54. whereas in the former case the information in the file is copied into
  55. the Registry.
  56. RegLoadKey requires SeRestorePrivilege.
  57. --*/
  58. {
  59. OBJECT_ATTRIBUTES ObjaKey;
  60. OBJECT_ATTRIBUTES ObjaFile;
  61. BOOLEAN ErrorFlag;
  62. UNICODE_STRING FileName;
  63. RTL_RELATIVE_NAME_U RelativeName;
  64. PVOID FreeBuffer;
  65. NTSTATUS NtStatus;
  66. PUNICODE_STRING SubKey;
  67. #if DBG
  68. //OutputDebugString( "WINREG: Entering BaseRegLoadKey\n" );
  69. #endif
  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. //
  75. // check for oddly formed UNICODE_STRINGs passed by malicious clients
  76. // check also for zero-length strings
  77. //
  78. if ((!lpFile->Length) ||
  79. (lpFile->Length & 1) ||
  80. (lpFile->Buffer[lpFile->Length/sizeof(WCHAR) - 1] != UNICODE_NULL)) {
  81. return ERROR_INVALID_PARAMETER;
  82. }
  83. if ((lpSubKey) &&
  84. ((!lpSubKey->Length) ||
  85. (lpSubKey->Length & 1) ||
  86. (lpSubKey->Buffer && (lpSubKey->Buffer[lpSubKey->Length/sizeof(WCHAR) - 1] != UNICODE_NULL)))) {
  87. return ERROR_INVALID_PARAMETER;
  88. }
  89. RPC_IMPERSONATE_CLIENT( NULL );
  90. //
  91. // Remove terminating NULLs from Length counts. These were added
  92. // on the client side so that RPC would transmit the whole thing.
  93. //
  94. if ( lpSubKey && lpSubKey->Length > 0 ) {
  95. lpSubKey->Length -= sizeof( UNICODE_NULL );
  96. SubKey = lpSubKey;
  97. } else {
  98. SubKey = NULL;
  99. }
  100. if ( lpFile->Length > 0 ) {
  101. lpFile->Length -= sizeof( UNICODE_NULL );
  102. }
  103. InitializeObjectAttributes(
  104. &ObjaKey,
  105. SubKey,
  106. OBJ_CASE_INSENSITIVE,
  107. hKey,
  108. NULL
  109. );
  110. //
  111. // Convert the DOS path name to a canonical Nt path name.
  112. //
  113. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
  114. lpFile->Buffer,
  115. &FileName,
  116. NULL,
  117. &RelativeName
  118. );
  119. //
  120. // If the name was not succesfully converted assume it was invalid.
  121. //
  122. if ( !ErrorFlag ) {
  123. RPC_REVERT_TO_SELF();
  124. return ERROR_INVALID_PARAMETER;
  125. }
  126. //
  127. // Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  128. //
  129. FreeBuffer = FileName.Buffer;
  130. //
  131. // If a relative name and directory handle will work, use those.
  132. //
  133. if ( RelativeName.RelativeName.Length ) {
  134. //
  135. // Replace the full path with the relative path.
  136. //
  137. FileName = RelativeName.RelativeName;
  138. } else {
  139. //
  140. // Using the full path - no containing directory.
  141. //
  142. RelativeName.ContainingDirectory = NULL;
  143. }
  144. //
  145. // Initialize the Obja structure for the file.
  146. //
  147. InitializeObjectAttributes(
  148. &ObjaFile,
  149. &FileName,
  150. OBJ_CASE_INSENSITIVE,
  151. RelativeName.ContainingDirectory,
  152. NULL
  153. );
  154. #if DBG
  155. //OutputDebugString( "WINREG: Before NtLoadKey\n" );
  156. #endif
  157. NtStatus = NtLoadKey(
  158. &ObjaKey,
  159. &ObjaFile
  160. );
  161. RtlReleaseRelativeName(&RelativeName);
  162. #if DBG
  163. //OutputDebugString( "WINREG: After RegLoadKey\n" );
  164. #endif
  165. RPC_REVERT_TO_SELF();
  166. //
  167. // Free the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  168. //
  169. RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
  170. #if DBG
  171. //OutputDebugString( "WINREG: Leaving BaseRegLoadKey\n" );
  172. #endif
  173. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  174. }
  175. error_status_t
  176. BaseRegUnLoadKey(
  177. IN HKEY hKey,
  178. IN PUNICODE_STRING lpSubKey OPTIONAL
  179. )
  180. /*++
  181. Routine Description:
  182. Unload the specified tree (hive) from the Registry.
  183. Arguments:
  184. hKey - Supplies a handle to an open key. lpSubKey is relative to this
  185. handle.
  186. lpSubKey - Supplies a path name to the key that is to be unloaded.
  187. The combination of hKey and lpSubKey must refer to a hive in the
  188. Registry created with RegRestoreKey or RegLoadKey. This parameter may
  189. be NULL.
  190. Return Value:
  191. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  192. RegUnLoadKey requires SeRestorePrivilege.
  193. --*/
  194. {
  195. OBJECT_ATTRIBUTES ObjaKey;
  196. NTSTATUS NtStatus;
  197. ASSERT( hKey != NULL );
  198. if ( (hKey == NULL) ||
  199. (lpSubKey && (lpSubKey->Length &1)) ) {
  200. return ERROR_INVALID_PARAMETER;
  201. }
  202. RPC_IMPERSONATE_CLIENT( NULL );
  203. //
  204. // Remove terminating NULLs from Length counts. These were added
  205. // on the client side so that RPC would transmit the whole thing.
  206. //
  207. if ( lpSubKey && lpSubKey->Length > 0 ) {
  208. lpSubKey->Length -= sizeof( UNICODE_NULL );
  209. }
  210. InitializeObjectAttributes(
  211. &ObjaKey,
  212. lpSubKey,
  213. OBJ_CASE_INSENSITIVE,
  214. hKey,
  215. NULL
  216. );
  217. NtStatus = NtUnloadKey( &ObjaKey );
  218. RPC_REVERT_TO_SELF();
  219. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  220. }
  221. error_status_t
  222. BaseRegReplaceKey(
  223. HKEY hKey,
  224. PUNICODE_STRING lpSubKey,
  225. PUNICODE_STRING lpNewFile,
  226. PUNICODE_STRING lpOldFile
  227. )
  228. /*++
  229. Routine Description:
  230. Replace an existing tree (hive) in the Registry. The new tree will
  231. take effect the next time the system is rebooted.
  232. Arguments:
  233. hKey - Supplies a handle to an open key. lpSubKey is relative to this
  234. handle.
  235. lpSubKey - Supplies a path name to the key that is to be replaced.
  236. The combination of hKey and lpSubKey must refer to a hive in the
  237. Registry. This parameter may be NULL.
  238. lpNewFile - Supplies a file name for the new hive file.
  239. lpOldFile - Supplies a backup file name for the old (existing) hive file.
  240. Return Value:
  241. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  242. Notes:
  243. lpNewFile will remain open until after the system is rebooted.
  244. RegUnLoadKey requires SeRestorePrivilege.
  245. --*/
  246. {
  247. UNICODE_STRING NewFileName;
  248. UNICODE_STRING OldFileName;
  249. RTL_RELATIVE_NAME_U NewRelativeName;
  250. RTL_RELATIVE_NAME_U OldRelativeName;
  251. PVOID NewFreeBuffer;
  252. PVOID OldFreeBuffer;
  253. HANDLE HiveHandle;
  254. OBJECT_ATTRIBUTES ObjaKey;
  255. OBJECT_ATTRIBUTES ObjaNewFile;
  256. OBJECT_ATTRIBUTES ObjaOldFile;
  257. BOOLEAN ErrorFlag;
  258. NTSTATUS NtStatus;
  259. ErrorFlag = (BOOLEAN)( (hKey == NULL) ||
  260. (lpNewFile == NULL) ||
  261. (lpNewFile->Buffer == NULL) ||
  262. (lpNewFile->Length & 1) ||
  263. (lpOldFile == NULL) ||
  264. (lpOldFile->Buffer == NULL) ||
  265. (lpOldFile->Length & 1) ||
  266. (lpSubKey && (lpSubKey->Length & 1))
  267. );
  268. ASSERT( !ErrorFlag );
  269. if ( ErrorFlag ) {
  270. return ERROR_INVALID_PARAMETER;
  271. }
  272. RPC_IMPERSONATE_CLIENT( NULL );
  273. //
  274. // Remove terminating NULLs from Length counts. These were added
  275. // on the client side so that RPC would transmit the whole thing.
  276. //
  277. if ( lpSubKey && lpSubKey->Length > 0 ) {
  278. lpSubKey->Length -= sizeof( UNICODE_NULL );
  279. }
  280. if ( lpNewFile->Length > 0 ) {
  281. lpNewFile->Length -= sizeof( UNICODE_NULL );
  282. }
  283. if ( lpOldFile->Length > 0 ) {
  284. lpOldFile->Length -= sizeof( UNICODE_NULL );
  285. }
  286. InitializeObjectAttributes(
  287. &ObjaKey,
  288. lpSubKey,
  289. OBJ_CASE_INSENSITIVE,
  290. hKey,
  291. NULL
  292. );
  293. //
  294. // Get a handle to the hive root
  295. //
  296. NtStatus = NtCreateKey(
  297. &HiveHandle,
  298. MAXIMUM_ALLOWED,
  299. &ObjaKey,
  300. 0,
  301. NULL,
  302. REG_OPTION_BACKUP_RESTORE,
  303. NULL
  304. );
  305. if ( !NT_SUCCESS( NtStatus ) ) {
  306. RPC_REVERT_TO_SELF();
  307. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  308. }
  309. //
  310. // Convert the new DOS path name to a canonical Nt path name.
  311. //
  312. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
  313. lpNewFile->Buffer,
  314. &NewFileName,
  315. NULL,
  316. &NewRelativeName
  317. );
  318. //
  319. // If the name was not succesfully converted assume it was invalid.
  320. //
  321. if ( !ErrorFlag ) {
  322. NtClose( HiveHandle );
  323. RPC_REVERT_TO_SELF();
  324. return ERROR_INVALID_PARAMETER;
  325. }
  326. //
  327. // Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  328. //
  329. NewFreeBuffer = NewFileName.Buffer;
  330. //
  331. // If a relative name and directory handle will work, use those.
  332. //
  333. if ( NewRelativeName.RelativeName.Length ) {
  334. //
  335. // Replace the full path with the relative path.
  336. //
  337. NewFileName = NewRelativeName.RelativeName;
  338. } else {
  339. //
  340. // Using the full path - no containing directory.
  341. //
  342. NewRelativeName.ContainingDirectory = NULL;
  343. }
  344. //
  345. // Initialize the Obja structure for the new file.
  346. //
  347. InitializeObjectAttributes(
  348. &ObjaNewFile,
  349. &NewFileName,
  350. OBJ_CASE_INSENSITIVE,
  351. NewRelativeName.ContainingDirectory,
  352. NULL
  353. );
  354. //
  355. // Convert the old DOS path name to a canonical Nt path name.
  356. //
  357. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
  358. lpOldFile->Buffer,
  359. &OldFileName,
  360. NULL,
  361. &OldRelativeName
  362. );
  363. //
  364. // If the name was not succesfully converted assume it was invalid.
  365. //
  366. if ( !ErrorFlag ) {
  367. RtlReleaseRelativeName(&NewRelativeName);
  368. RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
  369. NtClose( HiveHandle );
  370. RPC_REVERT_TO_SELF();
  371. return ERROR_INVALID_PARAMETER;
  372. }
  373. //
  374. // Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
  375. //
  376. OldFreeBuffer = OldFileName.Buffer;
  377. //
  378. // If a relative name and directory handle will work, use those.
  379. //
  380. if ( OldRelativeName.RelativeName.Length ) {
  381. //
  382. // Replace the full path with the relative path.
  383. //
  384. OldFileName = OldRelativeName.RelativeName;
  385. } else {
  386. //
  387. // Using the full path - no containing directory.
  388. //
  389. OldRelativeName.ContainingDirectory = NULL;
  390. }
  391. //
  392. // Initialize the Obja structure for the new file.
  393. //
  394. InitializeObjectAttributes(
  395. &ObjaOldFile,
  396. &OldFileName,
  397. OBJ_CASE_INSENSITIVE,
  398. OldRelativeName.ContainingDirectory,
  399. NULL
  400. );
  401. NtStatus = NtReplaceKey(
  402. &ObjaNewFile,
  403. HiveHandle,
  404. &ObjaOldFile
  405. );
  406. RtlReleaseRelativeName(&NewRelativeName);
  407. RtlReleaseRelativeName(&OldRelativeName);
  408. //
  409. // Free the buffers allocatted by RtlDosPathNameToRelativeNtPathName_U.
  410. //
  411. RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
  412. RtlFreeHeap( RtlProcessHeap( ), 0, OldFreeBuffer );
  413. NtClose( HiveHandle );
  414. RPC_REVERT_TO_SELF();
  415. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  416. }