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.

1233 lines
31 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. CmRegUtil.c
  5. Abstract:
  6. This module contains registry utility functions.
  7. Author:
  8. Adrian J. Oney - April 21, 2002
  9. Revision History:
  10. --*/
  11. #include "WlDef.h"
  12. #include "CmpRegutil.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, CmRegUtilOpenExistingUcKey)
  16. #pragma alloc_text(PAGE, CmRegUtilCreateUcKey)
  17. #pragma alloc_text(PAGE, CmRegUtilUcValueGetDword)
  18. #pragma alloc_text(PAGE, CmRegUtilUcValueGetFullBuffer)
  19. #pragma alloc_text(PAGE, CmRegUtilUcValueSetFullBuffer)
  20. #pragma alloc_text(PAGE, CmRegUtilUcValueSetUcString)
  21. #pragma alloc_text(PAGE, CmRegUtilOpenExistingWstrKey)
  22. #pragma alloc_text(PAGE, CmRegUtilCreateWstrKey)
  23. #pragma alloc_text(PAGE, CmRegUtilWstrValueGetDword)
  24. #pragma alloc_text(PAGE, CmRegUtilWstrValueGetFullBuffer)
  25. #pragma alloc_text(PAGE, CmRegUtilWstrValueSetFullBuffer)
  26. #pragma alloc_text(PAGE, CmRegUtilWstrValueSetUcString)
  27. #pragma alloc_text(PAGE, CmRegUtilUcValueSetWstrString)
  28. #pragma alloc_text(PAGE, CmRegUtilWstrValueSetWstrString)
  29. #pragma alloc_text(PAGE, CmpRegUtilAllocateUnicodeString)
  30. #pragma alloc_text(PAGE, CmpRegUtilFreeAllocatedUnicodeString)
  31. #endif
  32. #define POOLTAG_REGBUFFER 'bRpP'
  33. #define POOLTAG_UCSTRING 'cUpP'
  34. //
  35. // FUTURE WORK:
  36. // - Add function to read strings from registry
  37. // - Add function to read multisz strings from registry
  38. // - Add function to write multisz strings from registry
  39. // - Add function to create key *path* (see IopCreateRegistryKeyEx, who's
  40. // code should be cleaned up first)
  41. // - Add function to recursively delete keys
  42. //
  43. //
  44. // Unicode primitives - these are the best functions to use.
  45. //
  46. NTSTATUS
  47. CmRegUtilOpenExistingUcKey(
  48. IN HANDLE BaseHandle OPTIONAL,
  49. IN PUNICODE_STRING KeyName,
  50. IN ACCESS_MASK DesiredAccess,
  51. OUT HANDLE *Handle
  52. )
  53. /*++
  54. Routine Description:
  55. Opens a registry key using the name passed in based at the BaseHandle node.
  56. This name may specify a key that is actually a registry path.
  57. Arguments:
  58. BaseHandle - Optional handle to the base path from which the key must be
  59. opened. If this parameter is specified, then KeyName must be a relative
  60. path.
  61. KeyName - UNICODE_STRING Name of the Key that must be opened (either a full
  62. registry path, or a relative path depending on whether BaseHandle is
  63. supplied)
  64. DesiredAccess - Specifies the desired access that the caller needs to
  65. the key (this isn't really used as the access-mode is KernelMode,
  66. but we specify it anyway).
  67. Handle - Recieves registry key handle upon success, NULL otherwise.
  68. Note that the handle is in the global kernel namespace (and not the
  69. current processes handle take). The handle should be released using
  70. ZwClose.
  71. Return Value:
  72. STATUS_SUCCESS if the key could be opened, in which case Handle receives
  73. the registry key. Otherwise, failure is returned, and handle receives NULL.
  74. --*/
  75. {
  76. OBJECT_ATTRIBUTES objectAttributes;
  77. HANDLE newHandle;
  78. NTSTATUS status;
  79. PAGED_CODE();
  80. *Handle = NULL;
  81. InitializeObjectAttributes(
  82. &objectAttributes,
  83. KeyName,
  84. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  85. BaseHandle,
  86. (PSECURITY_DESCRIPTOR) NULL
  87. );
  88. //
  89. // Simply attempt to open the path, as specified.
  90. //
  91. status = ZwOpenKey(
  92. &newHandle,
  93. DesiredAccess,
  94. &objectAttributes
  95. );
  96. if (NT_SUCCESS(status)) {
  97. *Handle = newHandle;
  98. }
  99. return status;
  100. }
  101. NTSTATUS
  102. CmRegUtilCreateUcKey(
  103. IN HANDLE BaseHandle,
  104. IN PUNICODE_STRING KeyName,
  105. IN ACCESS_MASK DesiredAccess,
  106. IN ULONG CreateOptions,
  107. IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
  108. OUT ULONG *Disposition OPTIONAL,
  109. OUT HANDLE *Handle
  110. )
  111. /*++
  112. Routine Description:
  113. Opens or creates a registry key using the name passed in based at the
  114. BaseHandle node.
  115. Arguments:
  116. BaseHandle - Handle to the base path under which the key must be opened.
  117. KeyName - UNICODE_STRING Key Name that must be opened/created.
  118. DesiredAccess - Specifies the desired access that the caller needs to
  119. the key (this isn't really used as the access-mode is KernelMode,
  120. but we specify it anyway).
  121. CreateOptions - Options passed to ZwCreateKey. Examples:
  122. REG_OPTION_VOLATILE - Key is not to be stored across boots.
  123. REG_OPTION_NON_VOLATILE - Key is preserved when the system is rebooted.
  124. SecurityDescriptor - Security to apply if the key is newly created. If NULL,
  125. the key will inherit settings as defined by the inheritable properties
  126. of its parent.
  127. Disposition - This optional pointer receives a ULONG indicating whether
  128. the key was newly created (0 on error):
  129. REG_CREATED_NEW_KEY - A new Registry Key was created.
  130. REG_OPENED_EXISTING_KEY - An existing Registry Key was opened.
  131. Handle - Recieves registry key handle upon success, NULL otherwise.
  132. Note that the handle is in the global kernel namespace (and not the
  133. current processes handle take). The handle should be released using
  134. ZwClose.
  135. Return Value:
  136. The function value is the final status of the operation.
  137. --*/
  138. {
  139. OBJECT_ATTRIBUTES objectAttributes;
  140. ULONG disposition;
  141. HANDLE newHandle;
  142. NTSTATUS status;
  143. PAGED_CODE();
  144. InitializeObjectAttributes(
  145. &objectAttributes,
  146. KeyName,
  147. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  148. BaseHandle,
  149. SecurityDescriptor
  150. );
  151. //
  152. // Attempt to create the path as specified. We have to try it this
  153. // way first, because it allows us to create a key without a BaseHandle
  154. // (if only the last component of the registry path is not present).
  155. //
  156. status = ZwCreateKey(
  157. &newHandle,
  158. DesiredAccess,
  159. &objectAttributes,
  160. 0,
  161. (PUNICODE_STRING) NULL,
  162. CreateOptions,
  163. &disposition
  164. );
  165. //
  166. // Upon failure, populate the passed in parameters with consistant values
  167. // (this ensures determinisity if the calling code fails to properly check
  168. // the return value).
  169. //
  170. if (!NT_SUCCESS(status)) {
  171. newHandle = NULL;
  172. disposition = 0;
  173. }
  174. *Handle = newHandle;
  175. if (ARGUMENT_PRESENT(Disposition)) {
  176. *Disposition = disposition;
  177. }
  178. return status;
  179. }
  180. NTSTATUS
  181. CmRegUtilUcValueGetDword(
  182. IN HANDLE KeyHandle,
  183. IN PUNICODE_STRING ValueName,
  184. IN ULONG DefaultValue,
  185. OUT ULONG *Value
  186. )
  187. /*++
  188. Routine Description:
  189. This routine reads a dword value from the registry. The value name is
  190. specified in UNICODE_STRING form.
  191. Arguments:
  192. KeyHandle - Points to key to read.
  193. ValueName - Points to the value to read.
  194. DefaultValue - Points to the default value to use in case of an absence or
  195. error.
  196. Value - Receives DefaultValue on error, otherwise the value stored in the
  197. registry.
  198. Return Value:
  199. STATUS_SUCCESS if the value was present in the registry,
  200. STATUS_OBJECT_NAME_NOT_FOUND if it was absent,
  201. STATUS_OBJECT_TYPE_MISMATCH if the value was not a dword,
  202. or some other error value.
  203. --*/
  204. {
  205. UCHAR valueBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
  206. PKEY_VALUE_PARTIAL_INFORMATION keyInfo;
  207. ULONG keyValueLength;
  208. ULONG finalValue;
  209. NTSTATUS status;
  210. PAGED_CODE();
  211. //
  212. // Preinit
  213. //
  214. finalValue = DefaultValue;
  215. keyInfo = (PKEY_VALUE_PARTIAL_INFORMATION) valueBuffer;
  216. //
  217. // Read in the value
  218. //
  219. status = ZwQueryValueKey( KeyHandle,
  220. ValueName,
  221. KeyValuePartialInformation,
  222. (PVOID) valueBuffer,
  223. sizeof(valueBuffer),
  224. &keyValueLength
  225. );
  226. //
  227. // Fill in the output only as appropriate.
  228. //
  229. if (NT_SUCCESS(status)) {
  230. if (keyInfo->Type == REG_DWORD) {
  231. finalValue = *((PULONG) keyInfo->Data);
  232. } else {
  233. //
  234. // Closest error we can get...
  235. //
  236. status = STATUS_OBJECT_TYPE_MISMATCH;
  237. }
  238. }
  239. *Value = finalValue;
  240. return status;
  241. }
  242. NTSTATUS
  243. CmRegUtilUcValueGetFullBuffer(
  244. IN HANDLE KeyHandle,
  245. IN PUNICODE_STRING ValueName,
  246. IN ULONG DataType OPTIONAL,
  247. IN ULONG LikelyDataLength OPTIONAL,
  248. OUT PKEY_VALUE_FULL_INFORMATION *Information
  249. )
  250. /*++
  251. Routine Description:
  252. This routine is invoked to retrieve the data for a registry key's value.
  253. This is done by querying the value of the key with a zero-length buffer
  254. to determine the size of the value, and then allocating a buffer and
  255. actually querying the value into the buffer.
  256. It is the responsibility of the caller to free the buffer.
  257. Arguments:
  258. KeyHandle - Supplies the key handle whose value is to be queried
  259. ValueName - Supplies the Unicode string name of the value.
  260. DataType - REG_NONE if any type is allowable, otherwise the specific type
  261. required.
  262. LikelyDataLength - An optional parameter to eliminate unneccessary
  263. allocations and reparses.
  264. Information - Receives a pointer to the allocated data buffer allocated
  265. from PagedPool, NULL on error. If successful, the buffer
  266. should be freed using ExFreePool.
  267. Note - the allocated memory is *not* charged against the
  268. calling process.
  269. Return Value:
  270. STATUS_SUCCESS if the information was retrievable, error otherwise (in
  271. which case Information will receive NULL).
  272. --*/
  273. {
  274. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  275. ULONG keyValueLength, guessSize;
  276. NTSTATUS status;
  277. PAGED_CODE();
  278. //
  279. // Preinit for error
  280. //
  281. *Information = NULL;
  282. //
  283. // Set an initial size to try when loading a key. Note that
  284. // KeyValueFullInformation already comes with a single WCHAR of data.
  285. //
  286. guessSize = (ULONG)(sizeof(KEY_VALUE_FULL_INFORMATION) + ValueName->Length);
  287. //
  288. // Now round up to a natural alignment. This needs to be done because our
  289. // data member will naturally aligned as well.
  290. //
  291. guessSize = (ULONG) ALIGN_POINTER_OFFSET(guessSize);
  292. //
  293. // Adjust for the most likely size of the data.
  294. //
  295. guessSize += LikelyDataLength;
  296. infoBuffer = ExAllocatePoolWithTag(
  297. NonPagedPool,
  298. guessSize,
  299. POOLTAG_REGBUFFER
  300. );
  301. if (infoBuffer == NULL) {
  302. return STATUS_INSUFFICIENT_RESOURCES;
  303. }
  304. //
  305. // Figure out how big the data value is so that a buffer of the
  306. // appropriate size can be allocated.
  307. //
  308. status = ZwQueryValueKey(
  309. KeyHandle,
  310. ValueName,
  311. KeyValueFullInformation,
  312. (PVOID) infoBuffer,
  313. guessSize,
  314. &keyValueLength
  315. );
  316. if (NT_SUCCESS(status)) {
  317. //
  318. // First guess worked, bail!
  319. //
  320. goto Success;
  321. }
  322. ExFreePool(infoBuffer);
  323. if (status != STATUS_BUFFER_OVERFLOW &&
  324. status != STATUS_BUFFER_TOO_SMALL) {
  325. ASSERT(!NT_SUCCESS(status));
  326. return status;
  327. }
  328. //
  329. // Allocate a buffer large enough to contain the entire key data value.
  330. //
  331. infoBuffer = ExAllocatePoolWithTag(
  332. NonPagedPool,
  333. keyValueLength,
  334. POOLTAG_REGBUFFER
  335. );
  336. if (infoBuffer == NULL) {
  337. return STATUS_INSUFFICIENT_RESOURCES;
  338. }
  339. //
  340. // Query the data for the key value.
  341. //
  342. status = ZwQueryValueKey(
  343. KeyHandle,
  344. ValueName,
  345. KeyValueFullInformation,
  346. infoBuffer,
  347. keyValueLength,
  348. &keyValueLength
  349. );
  350. if (!NT_SUCCESS( status )) {
  351. ExFreePool(infoBuffer);
  352. return status;
  353. }
  354. Success:
  355. //
  356. // One last check - validate the type field
  357. //
  358. if ((DataType != REG_NONE) && (infoBuffer->Type != DataType)) {
  359. //
  360. // Mismatched type - bail.
  361. //
  362. ExFreePool(infoBuffer);
  363. //
  364. // Closest error we can get...
  365. //
  366. return STATUS_OBJECT_TYPE_MISMATCH;
  367. }
  368. //
  369. // Everything worked, so simply return the address of the allocated
  370. // buffer to the caller, who is now responsible for freeing it.
  371. //
  372. *Information = infoBuffer;
  373. return STATUS_SUCCESS;
  374. }
  375. NTSTATUS
  376. CmRegUtilUcValueSetFullBuffer(
  377. IN HANDLE KeyHandle,
  378. IN PUNICODE_STRING ValueName,
  379. IN ULONG DataType,
  380. IN PVOID Buffer,
  381. IN ULONG BufferSize
  382. )
  383. /*++
  384. Routine Description:
  385. This function writes a buffer of information to a specific value key in
  386. the registry.
  387. Parameters:
  388. KeyHandle - A handle to the key under which the value is stored.
  389. ValueName - Supplies a pointer to the UNICODE_STRING name of the value key.
  390. DataType - Specifies the type of data to write.
  391. Buffer - Points to the buffer to write.
  392. BufferSize - Specifies the size of the buffer to write.
  393. Return Value:
  394. Status code that indicates whether or not the function was successful.
  395. --*/
  396. {
  397. PAGED_CODE();
  398. return ZwSetValueKey(
  399. KeyHandle,
  400. ValueName,
  401. 0,
  402. DataType,
  403. Buffer,
  404. BufferSize
  405. );
  406. }
  407. NTSTATUS
  408. CmRegUtilUcValueSetUcString(
  409. IN HANDLE KeyHandle,
  410. IN PUNICODE_STRING ValueName,
  411. IN PUNICODE_STRING ValueData
  412. )
  413. /*++
  414. Routine Description:
  415. Sets a value key in the registry to a specific value of string (REG_SZ) type.
  416. Parameters:
  417. KeyHandle - A handle to the key under which the value is stored.
  418. ValueName - Supplies a pointer to the UNICODE_STRING name of the value key
  419. ValueData - Supplies a pointer to the string to be stored in the key. The
  420. data will automatically be null terminated for storage in the registry.
  421. Return Value:
  422. Status code that indicates whether or not the function was successful.
  423. --*/
  424. {
  425. UNICODE_STRING tempString;
  426. NTSTATUS status;
  427. PAGED_CODE();
  428. ASSERT(ValueName);
  429. ASSERT(ValueData);
  430. ASSERT(ValueName->Buffer);
  431. ASSERT(ValueData->Buffer);
  432. //
  433. // Null terminate the string
  434. //
  435. if ((ValueData->MaximumLength - ValueData->Length) >= sizeof(UNICODE_NULL)) {
  436. //
  437. // There is room in the buffer so just append a null
  438. //
  439. ValueData->Buffer[(ValueData->Length / sizeof(WCHAR))] = UNICODE_NULL;
  440. //
  441. // Set the registry value
  442. //
  443. status = ZwSetValueKey(
  444. KeyHandle,
  445. ValueName,
  446. 0,
  447. REG_SZ,
  448. (PVOID) ValueData->Buffer,
  449. ValueData->Length + sizeof(UNICODE_NULL)
  450. );
  451. } else {
  452. //
  453. // There is no room so allocate a new buffer and so we need to build
  454. // a new string with room
  455. //
  456. status = CmpRegUtilAllocateUnicodeString(&tempString, ValueData->Length);
  457. if (!NT_SUCCESS(status)) {
  458. goto clean0;
  459. }
  460. //
  461. // Copy the input string to the output string
  462. //
  463. tempString.Length = ValueData->Length;
  464. RtlCopyMemory(tempString.Buffer, ValueData->Buffer, ValueData->Length);
  465. //
  466. // Add the null termination
  467. //
  468. tempString.Buffer[tempString.Length / sizeof(WCHAR)] = UNICODE_NULL;
  469. //
  470. // Set the registry value
  471. //
  472. status = ZwSetValueKey(
  473. KeyHandle,
  474. ValueName,
  475. 0,
  476. REG_SZ,
  477. (PVOID) tempString.Buffer,
  478. tempString.Length + sizeof(UNICODE_NULL)
  479. );
  480. //
  481. // Free the temporary string
  482. //
  483. CmpRegUtilFreeAllocatedUnicodeString(&tempString);
  484. }
  485. clean0:
  486. return status;
  487. }
  488. //
  489. // WSTR and mixed primitives
  490. //
  491. NTSTATUS
  492. CmRegUtilOpenExistingWstrKey(
  493. IN HANDLE BaseHandle OPTIONAL,
  494. IN PWSTR KeyName,
  495. IN ACCESS_MASK DesiredAccess,
  496. OUT HANDLE *Handle
  497. )
  498. /*++
  499. Routine Description:
  500. Opens a registry key using the name passed in based at the BaseHandle node.
  501. This name may specify a key that is actually a registry path.
  502. Arguments:
  503. BaseHandle - Optional handle to the base path from which the key must be
  504. opened. If this parameter is specified, then KeyName must be a relative
  505. path.
  506. KeyName - WSTR Name of the Key that must be opened (either a full registry
  507. path, or a relative path depending on whether BaseHandle is supplied)
  508. DesiredAccess - Specifies the desired access that the caller needs to
  509. the key (this isn't really used, as the access-mode is KernelMode,
  510. but we specify it anyway).
  511. Handle - Recieves registry key handle upon success, NULL otherwise.
  512. Note that the handle is in the global kernel namespace (and not the
  513. current processes handle take). The handle should be released using
  514. ZwClose.
  515. Return Value:
  516. STATUS_SUCCESS if the key could be opened, in which case Handle receives
  517. the registry key. Otherwise, failure is returned, and handle receives NULL.
  518. --*/
  519. {
  520. UNICODE_STRING unicodeStringKeyName;
  521. NTSTATUS status;
  522. PAGED_CODE();
  523. status = RtlInitUnicodeStringEx(&unicodeStringKeyName, KeyName);
  524. if (!NT_SUCCESS(status)) {
  525. return status;
  526. }
  527. return CmRegUtilOpenExistingUcKey(
  528. BaseHandle,
  529. &unicodeStringKeyName,
  530. DesiredAccess,
  531. Handle
  532. );
  533. }
  534. NTSTATUS
  535. CmRegUtilCreateWstrKey(
  536. IN HANDLE BaseHandle,
  537. IN PWSTR KeyName,
  538. IN ACCESS_MASK DesiredAccess,
  539. IN ULONG CreateOptions,
  540. IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
  541. OUT ULONG *Disposition OPTIONAL,
  542. OUT HANDLE *Handle
  543. )
  544. /*++
  545. Routine Description:
  546. Opens or creates a registry key using the name passed in based at the
  547. BaseHandle node.
  548. Arguments:
  549. BaseHandle - Handle to the base path under which the key must be opened.
  550. KeyName - WSTR Key Name that must be opened/created.
  551. DesiredAccess - Specifies the desired access that the caller needs to
  552. the key (this isn't really used as the access-mode is KernelMode,
  553. but we specify it anyway).
  554. CreateOptions - Options passed to ZwCreateKey. Examples:
  555. REG_OPTION_VOLATILE - Key is not to be stored across boots.
  556. REG_OPTION_NON_VOLATILE - Key is preserved when the system is rebooted.
  557. SecurityDescriptor - Security to apply if the key is newly created. If NULL,
  558. the key will inherit settings as defined by the inheritable properties
  559. of its parent.
  560. Disposition - This optional pointer receives a ULONG indicating whether
  561. the key was newly created (0 on error):
  562. REG_CREATED_NEW_KEY - A new Registry Key was created.
  563. REG_OPENED_EXISTING_KEY - An existing Registry Key was opened.
  564. Handle - Recieves registry key handle upon success, NULL otherwise.
  565. Note that the handle is in the global kernel namespace (and not the
  566. current processes handle take). The handle should be released using
  567. ZwClose.
  568. Return Value:
  569. The function value is the final status of the operation.
  570. --*/
  571. {
  572. UNICODE_STRING unicodeStringKeyName;
  573. NTSTATUS status;
  574. PAGED_CODE();
  575. status = RtlInitUnicodeStringEx(&unicodeStringKeyName, KeyName);
  576. if (!NT_SUCCESS(status)) {
  577. return status;
  578. }
  579. return CmRegUtilCreateUcKey(
  580. BaseHandle,
  581. &unicodeStringKeyName,
  582. DesiredAccess,
  583. CreateOptions,
  584. SecurityDescriptor,
  585. Disposition,
  586. Handle
  587. );
  588. }
  589. NTSTATUS
  590. CmRegUtilWstrValueGetDword(
  591. IN HANDLE KeyHandle,
  592. IN PWSTR ValueName,
  593. IN ULONG DefaultValue,
  594. OUT ULONG *Value
  595. )
  596. /*++
  597. Routine Description:
  598. This routine reads a dword value from the registry. The value name is
  599. specified in WSTR form.
  600. Arguments:
  601. KeyHandle - Points to key to read.
  602. ValueName - Points to the value to read.
  603. DefaultValue - Points to the default value to use in case of an absence or
  604. error.
  605. Value - Receives DefaultValue on error, otherwise the value stored in the
  606. registry.
  607. Return Value:
  608. STATUS_SUCCESS if the value was present in the registry,
  609. STATUS_OBJECT_NAME_NOT_FOUND if it was absent,
  610. STATUS_OBJECT_TYPE_MISMATCH if the value was not a dword,
  611. or some other error value.
  612. --*/
  613. {
  614. UNICODE_STRING unicodeStringValueName;
  615. NTSTATUS status;
  616. PAGED_CODE();
  617. //
  618. // Construct the unicode name
  619. //
  620. status = RtlInitUnicodeStringEx(&unicodeStringValueName, ValueName);
  621. if (!NT_SUCCESS(status)) {
  622. return status;
  623. }
  624. return CmRegUtilUcValueGetDword(
  625. KeyHandle,
  626. &unicodeStringValueName,
  627. DefaultValue,
  628. Value
  629. );
  630. }
  631. NTSTATUS
  632. CmRegUtilWstrValueGetFullBuffer(
  633. IN HANDLE KeyHandle,
  634. IN PWSTR ValueName,
  635. IN ULONG DataType OPTIONAL,
  636. IN ULONG LikelyDataLength OPTIONAL,
  637. OUT PKEY_VALUE_FULL_INFORMATION *Information
  638. )
  639. /*++
  640. Routine Description:
  641. This routine is invoked to retrieve the data for a registry key's value.
  642. This is done by querying the value of the key with a zero-length buffer
  643. to determine the size of the value, and then allocating a buffer and
  644. actually querying the value into the buffer.
  645. It is the responsibility of the caller to free the buffer.
  646. Arguments:
  647. KeyHandle - Supplies the key handle whose value is to be queried
  648. ValueName - Supplies the null-terminated WSTR name of the value.
  649. DataType - REG_NONE if any type is allowable, otherwise the specific type
  650. required.
  651. LikelyDataLength - Most likely size of the data to retrieve (used to
  652. optimize queries).
  653. Information - Receives a pointer to the allocated data buffer allocated
  654. from PagedPool, NULL on error. If successful, the buffer
  655. should be freed using ExFreePool.
  656. Note - the allocated memory is *not* charged against the
  657. calling process.
  658. Return Value:
  659. STATUS_SUCCESS if the information was retrievable, error otherwise (in
  660. which case Information will receive NULL).
  661. --*/
  662. {
  663. UNICODE_STRING unicodeStringValueName;
  664. NTSTATUS status;
  665. PAGED_CODE();
  666. //
  667. // Construct the unicode name
  668. //
  669. status = RtlInitUnicodeStringEx(&unicodeStringValueName, ValueName);
  670. if (!NT_SUCCESS(status)) {
  671. return status;
  672. }
  673. return CmRegUtilUcValueGetFullBuffer(
  674. KeyHandle,
  675. &unicodeStringValueName,
  676. DataType,
  677. LikelyDataLength,
  678. Information
  679. );
  680. }
  681. NTSTATUS
  682. CmRegUtilWstrValueSetFullBuffer(
  683. IN HANDLE KeyHandle,
  684. IN PWSTR ValueName,
  685. IN ULONG DataType,
  686. IN PVOID Buffer,
  687. IN ULONG BufferSize
  688. )
  689. /*++
  690. Routine Description:
  691. This function writes a buffer of information to a specific value key in
  692. the registry.
  693. Parameters:
  694. KeyHandle - A handle to the key under which the value is stored.
  695. ValueName - Supplies a pointer to the WSTR name of the value key.
  696. DataType - Specifies the type of data to write.
  697. Buffer - Points to the buffer to write.
  698. BufferSize - Specifies the size of the buffer to write.
  699. Return Value:
  700. Status code that indicates whether or not the function was successful.
  701. --*/
  702. {
  703. UNICODE_STRING unicodeStringValueName;
  704. NTSTATUS status;
  705. PAGED_CODE();
  706. //
  707. // Construct the unicode name
  708. //
  709. status = RtlInitUnicodeStringEx(&unicodeStringValueName, ValueName);
  710. if (!NT_SUCCESS(status)) {
  711. return status;
  712. }
  713. return CmRegUtilUcValueSetFullBuffer(
  714. KeyHandle,
  715. &unicodeStringValueName,
  716. DataType,
  717. Buffer,
  718. BufferSize
  719. );
  720. }
  721. NTSTATUS
  722. CmRegUtilWstrValueSetUcString(
  723. IN HANDLE KeyHandle,
  724. IN PWSTR ValueName,
  725. IN PUNICODE_STRING ValueData
  726. )
  727. /*++
  728. Routine Description:
  729. Sets a value key in the registry to a specific value of string (REG_SZ) type.
  730. The value name is specified in WSTR form, while the value data is in
  731. UNICODE_STRING format.
  732. Parameters:
  733. KeyHandle - A handle to the key under which the value is stored.
  734. ValueName - Supplies a WSTR pointer to the name of the value key
  735. ValueData - Supplies a pointer to the string to be stored in the key. The
  736. data will automatically be null terminated for storage in the registry.
  737. Return Value:
  738. Status code that indicates whether or not the function was successful.
  739. --*/
  740. {
  741. UNICODE_STRING unicodeStringValueName;
  742. NTSTATUS status;
  743. PAGED_CODE();
  744. ASSERT(ValueName);
  745. ASSERT(ValueData);
  746. ASSERT(ValueData->Buffer);
  747. //
  748. // Construct the unicode name
  749. //
  750. status = RtlInitUnicodeStringEx(&unicodeStringValueName, ValueName);
  751. if (!NT_SUCCESS(status)) {
  752. return status;
  753. }
  754. return CmRegUtilUcValueSetUcString(
  755. KeyHandle,
  756. &unicodeStringValueName,
  757. ValueData
  758. );
  759. }
  760. NTSTATUS
  761. CmRegUtilUcValueSetWstrString(
  762. IN HANDLE KeyHandle,
  763. IN PUNICODE_STRING ValueName,
  764. IN PWSTR ValueData
  765. )
  766. /*++
  767. Routine Description:
  768. Sets a value key in the registry to a specific value of string (REG_SZ) type.
  769. Parameters:
  770. KeyHandle - A handle to the key under which the value is stored.
  771. ValueName - Supplies a pointer to the UNICODE_STRING name of the value key
  772. ValueData - Supplies a pointer to the string to be stored in the key. The
  773. data will automatically be null terminated for storage in the registry.
  774. Return Value:
  775. Status code that indicates whether or not the function was successful.
  776. --*/
  777. {
  778. UNICODE_STRING valueString;
  779. NTSTATUS status;
  780. PAGED_CODE();
  781. ASSERT(ValueName);
  782. ASSERT(ValueData);
  783. ASSERT(ValueName->Buffer);
  784. //
  785. // Construct the unicode data
  786. //
  787. status = RtlInitUnicodeStringEx(&valueString, ValueData);
  788. if (!NT_SUCCESS(status)) {
  789. return status;
  790. }
  791. return CmRegUtilUcValueSetUcString(
  792. KeyHandle,
  793. ValueName,
  794. &valueString
  795. );
  796. }
  797. NTSTATUS
  798. CmRegUtilWstrValueSetWstrString(
  799. IN HANDLE KeyHandle,
  800. IN PWSTR ValueName,
  801. IN PWSTR ValueData
  802. )
  803. /*++
  804. Routine Description:
  805. Sets a value key in the registry to a specific value of string (REG_SZ) type.
  806. Parameters:
  807. KeyHandle - A handle to the key under which the value is stored.
  808. ValueName - Supplies a pointer to the WSTR name of the value key
  809. ValueData - Supplies a pointer to the string to be stored in the key. The
  810. data will automatically be null terminated for storage in the registry.
  811. Return Value:
  812. Status code that indicates whether or not the function was successful.
  813. --*/
  814. {
  815. UNICODE_STRING unicodeStringValueName;
  816. UNICODE_STRING valueString;
  817. NTSTATUS status;
  818. PAGED_CODE();
  819. ASSERT(ValueName);
  820. ASSERT(ValueData);
  821. //
  822. // Construct the unicode data
  823. //
  824. status = RtlInitUnicodeStringEx(&valueString, ValueData);
  825. if (!NT_SUCCESS(status)) {
  826. return status;
  827. }
  828. //
  829. // Construct the unicode name
  830. //
  831. status = RtlInitUnicodeStringEx(&unicodeStringValueName, ValueName);
  832. if (!NT_SUCCESS(status)) {
  833. return status;
  834. }
  835. return CmRegUtilUcValueSetUcString(
  836. KeyHandle,
  837. &unicodeStringValueName,
  838. &valueString
  839. );
  840. }
  841. NTSTATUS
  842. CmpRegUtilAllocateUnicodeString(
  843. IN OUT PUNICODE_STRING String,
  844. IN USHORT Length
  845. )
  846. /*++
  847. Routine Description:
  848. This routine allocates a buffer for a unicode string of a given length
  849. and initialises the UNICODE_STRING structure appropriately. When the
  850. string is no longer required it can be freed using
  851. CmpRegUtilFreeAllocatedString. The buffer also can be directly deleted by
  852. ExFreePool and so can be handed back to a caller.
  853. Parameters:
  854. String - Supplies a pointer to an uninitialised unicode string which will
  855. be manipulated by the function.
  856. Length - The number of BYTES long that the string will be.
  857. Return Value:
  858. Either STATUS_INSUFFICIENT_RESOURCES indicating paged pool is exhausted or
  859. STATUS_SUCCESS.
  860. Remarks:
  861. The buffer allocated will be one character (2 bytes) more than length specified.
  862. This is to allow for easy null termination of the strings - eg for registry
  863. storage.
  864. --*/
  865. {
  866. PAGED_CODE();
  867. String->Length = 0;
  868. String->MaximumLength = Length + sizeof(UNICODE_NULL);
  869. String->Buffer = ExAllocatePoolWithTag(
  870. PagedPool,
  871. Length + sizeof(UNICODE_NULL),
  872. POOLTAG_UCSTRING
  873. );
  874. if (String->Buffer == NULL) {
  875. return STATUS_INSUFFICIENT_RESOURCES;
  876. } else {
  877. return STATUS_SUCCESS;
  878. }
  879. }
  880. VOID
  881. CmpRegUtilFreeAllocatedUnicodeString(
  882. IN PUNICODE_STRING String
  883. )
  884. /*++
  885. Routine Description:
  886. This routine frees a string previously allocated with
  887. CmpRegUtilAllocateUnicodeString.
  888. Parameters:
  889. String - Supplies a pointer to the string that has been previously allocated.
  890. Return Value:
  891. None
  892. --*/
  893. {
  894. PAGED_CODE();
  895. ASSERT(String);
  896. RtlFreeUnicodeString(String);
  897. }