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.

1227 lines
30 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. RegvCls.c
  5. Abstract:
  6. This module contains helper functions for enumerating,
  7. setting, and querying registry values in win32
  8. Author:
  9. Adam Edwards (adamed) 06-May-1998
  10. Key Functions:
  11. Notes:
  12. --*/
  13. #ifdef LOCAL
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "localreg.h"
  17. #include "regclass.h"
  18. #include "regvcls.h"
  19. void ValStateGetPhysicalIndexFromLogical(
  20. ValueState* pValState,
  21. HKEY hkLogicalKey,
  22. DWORD dwLogicalIndex,
  23. PHKEY phkPhysicalKey,
  24. DWORD* pdwPhysicalIndex)
  25. /*++
  26. Routine Description:
  27. Retrieves a logical index for a value to a physical index
  28. Arguments:
  29. pValState - value state containing values for a logical key
  30. hkLogicalKey - logical key we wish to index
  31. dwLogicalIndex - logical index to map
  32. phkPhysicalKey - handle to key where value is physically located
  33. pdwPhysicalIndex - index of value in physical key
  34. Return Value:
  35. None.
  36. Notes:
  37. --*/
  38. {
  39. //
  40. // If no value state is supplied, this means no merging is necessary
  41. // and we can return the supplied logical index as the correct
  42. // physical index
  43. //
  44. if (!pValState) {
  45. *pdwPhysicalIndex = dwLogicalIndex;
  46. *phkPhysicalKey = hkLogicalKey;
  47. } else {
  48. *pdwPhysicalIndex = pValState->rgIndex[dwLogicalIndex].dwOffset;
  49. *phkPhysicalKey = pValState->rgIndex[dwLogicalIndex].fUser ?
  50. pValState->hkUser :
  51. pValState->hkMachine;
  52. }
  53. }
  54. NTSTATUS ValStateSetPhysicalIndexFromLogical(
  55. ValueState* pValState,
  56. DWORD dwLogicalIndex)
  57. /*++
  58. Routine Description:
  59. Updates a state's mapping of logical indexes to physical indexes
  60. Arguments:
  61. pValState - value state containing values for a logical key
  62. dwLogicalIndex - logical index used as a clue for whether
  63. or not we can used cached values or need to refresh the state --
  64. gives us an idea of what index the caller will be interested in
  65. mapping after this call.
  66. Return Value:
  67. None.
  68. Notes:
  69. --*/
  70. {
  71. NTSTATUS Status;
  72. Status = STATUS_SUCCESS;
  73. //
  74. // If no value state is supplied, this means no merging is necessary
  75. // and we can return the supplied logical index as the correct
  76. // physical index
  77. //
  78. if (!pValState) {
  79. return STATUS_SUCCESS;
  80. }
  81. if (dwLogicalIndex >= pValState->cValues) {
  82. pValState->fDelete = TRUE;
  83. return STATUS_NO_MORE_ENTRIES;
  84. }
  85. //
  86. // Always reset if they try to go backward, or
  87. // if they skip by more than 1, or if they
  88. // ask for the same index twice and we're
  89. // not expecting it
  90. //
  91. if ((dwLogicalIndex < pValState->dwCurrent) ||
  92. (dwLogicalIndex > (pValState->dwCurrent + 1)) ||
  93. ((dwLogicalIndex == pValState->dwCurrent) && !(pValState->fIgnoreResetOnRetry))) {
  94. Status = ValStateUpdate(pValState);
  95. if (!NT_SUCCESS(Status)) {
  96. return Status;
  97. }
  98. pValState->fIgnoreResetOnRetry = FALSE;
  99. }
  100. return Status;
  101. }
  102. void ValStateRelease(
  103. ValueState* pValState)
  104. /*++
  105. Routine Description:
  106. Frees resources (handles, memory) associated with a value state
  107. Arguments:
  108. pValState - value state containing values for a logical key
  109. Return Value:
  110. None.
  111. Notes:
  112. --*/
  113. {
  114. if (!pValState) {
  115. return;
  116. }
  117. if (pValState->hkUser && (pValState->hkUser != pValState->hkLogical)) {
  118. NtClose(pValState->hkUser);
  119. }
  120. if (pValState->hkMachine && (pValState->hkMachine != pValState->hkLogical)) {
  121. NtClose(pValState->hkMachine);
  122. }
  123. if (pValState->rgIndex) {
  124. RegClassHeapFree(pValState->rgIndex);
  125. }
  126. RegClassHeapFree(pValState);
  127. }
  128. NTSTATUS ValStateUpdate(ValueState* pValState)
  129. /*++
  130. Routine Description:
  131. Updates the value state to reflect the current state
  132. of the logical key's physical state -- it retrieves
  133. the names of the values for the logical key from
  134. the kernel, and re-indexes the table to properly
  135. merge user and machine state
  136. Arguments:
  137. pValState - value state containing values for a logical key
  138. Return Value:
  139. STATUS_SUCCESS for success, error code otherwise.
  140. Notes:
  141. --*/
  142. {
  143. NTSTATUS Status;
  144. DWORD cUserValues;
  145. DWORD cMachineValues;
  146. DWORD cMaxValues;
  147. DWORD cbMaxNameLen;
  148. DWORD cbMaxDataLen;
  149. DWORD cbBufferLen;
  150. ValueLocation* rgIndex;
  151. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo;
  152. //
  153. // Init locals
  154. //
  155. cUserValues = 0;
  156. cMachineValues = 0;
  157. cbMaxNameLen = 0;
  158. rgIndex = NULL;
  159. pValState->cValues = 0;
  160. //
  161. // Get information about this value
  162. //
  163. Status = GetFixedKeyInfo(
  164. pValState->hkUser,
  165. pValState->hkMachine,
  166. &cUserValues,
  167. &cMachineValues,
  168. NULL,
  169. NULL,
  170. &cbMaxNameLen);
  171. if (!NT_SUCCESS(Status)) {
  172. return Status;
  173. }
  174. cMaxValues = cUserValues + cMachineValues;
  175. //
  176. // Nothing to do if there are no Values
  177. //
  178. if (!cMaxValues) {
  179. return STATUS_SUCCESS;
  180. }
  181. //
  182. // Now allocate necessary memory
  183. // First get memory for index vector
  184. //
  185. rgIndex = (ValueLocation*) RegClassHeapAlloc(cMaxValues * sizeof(*rgIndex));
  186. if (!rgIndex) {
  187. return STATUS_NO_MEMORY;
  188. }
  189. //
  190. // Now get memory for retrieving names -- first allocate an array
  191. // of pointers to values
  192. //
  193. ppValueInfo = (PKEY_VALUE_BASIC_INFORMATION*) RegClassHeapAlloc(
  194. sizeof(*ppValueInfo) * cMaxValues);
  195. if (!ppValueInfo) {
  196. RegClassHeapFree(rgIndex);
  197. return STATUS_NO_MEMORY;
  198. }
  199. RtlZeroMemory(ppValueInfo, sizeof(*ppValueInfo) * cMaxValues);
  200. cbBufferLen = sizeof(**ppValueInfo) + cbMaxNameLen;
  201. //
  202. // Now allocate each individual value
  203. //
  204. {
  205. DWORD dwValue;
  206. for (dwValue = 0; dwValue < cMaxValues; dwValue++)
  207. {
  208. ppValueInfo[dwValue] = (PKEY_VALUE_BASIC_INFORMATION) RegClassHeapAlloc(
  209. cbBufferLen);
  210. if (!(ppValueInfo)[dwValue]) {
  211. Status = STATUS_NO_MEMORY;
  212. break;
  213. }
  214. }
  215. }
  216. //
  217. // Now fetch the values. From this point on we are assuming success
  218. // and updating the index table
  219. //
  220. {
  221. HKEY hKeyPhysical;
  222. DWORD dwLimit;
  223. DWORD dwLogical;
  224. BOOL fUser;
  225. //
  226. // Free the existing index table
  227. //
  228. if (pValState->rgIndex) {
  229. RegClassHeapFree(pValState->rgIndex);
  230. }
  231. pValState->rgIndex = rgIndex;
  232. dwLogical = 0;
  233. for( hKeyPhysical = pValState->hkUser, fUser = TRUE,
  234. dwLimit = cUserValues;
  235. ;
  236. hKeyPhysical = pValState->hkMachine, fUser = FALSE,
  237. dwLimit = cMachineValues)
  238. {
  239. DWORD dwPhysical;
  240. for (dwPhysical = 0; dwPhysical < dwLimit; dwPhysical++)
  241. {
  242. BOOL fNewValue;
  243. //
  244. // Ask the kernel for the value
  245. //
  246. Status = EnumerateValue(
  247. hKeyPhysical,
  248. dwPhysical,
  249. ppValueInfo[dwLogical],
  250. cbBufferLen,
  251. NULL);
  252. //
  253. // If we encounter an error, just keep going and try to get
  254. // as many values as we can
  255. //
  256. if (!NT_SUCCESS(Status)) {
  257. continue;
  258. }
  259. //
  260. // Mark certain attributes about this value that will
  261. // be important later
  262. //
  263. ppValueInfo[dwLogical]->TitleIndex = dwPhysical;
  264. ppValueInfo[dwLogical]->Type = fUser;
  265. //
  266. // This will add the value to our sorted list. Since
  267. // the list is sorted, it is easy to eliminated duplicates --
  268. // don't add duplicates -- since we add
  269. // user keys first, this allows us to give user values precedence
  270. // over machine values of the same name. The logical key
  271. // index is also incremented if a key is added.
  272. //
  273. fNewValue = ValStateAddValueToSortedValues(
  274. ppValueInfo,
  275. dwLogical);
  276. if (fNewValue) {
  277. dwLogical++;
  278. }
  279. }
  280. //
  281. // Break out of this loop if we just added the user values
  282. // since those are the last values we add
  283. //
  284. if (!fUser) {
  285. break;
  286. }
  287. }
  288. pValState->cValues = dwLogical;
  289. }
  290. //
  291. // Now copy the results back to the state's index array
  292. //
  293. {
  294. DWORD dwLogical;
  295. for (dwLogical = 0; dwLogical < pValState->cValues; dwLogical++)
  296. {
  297. pValState->rgIndex[dwLogical].dwOffset =
  298. ppValueInfo[dwLogical]->TitleIndex;
  299. pValState->rgIndex[dwLogical].fUser =
  300. ppValueInfo[dwLogical]->Type;
  301. }
  302. }
  303. //
  304. // Release this
  305. //
  306. ValStateReleaseValues(
  307. ppValueInfo,
  308. cMaxValues);
  309. return STATUS_SUCCESS;
  310. }
  311. void ValStateReleaseValues(
  312. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo,
  313. DWORD cMaxValues)
  314. /*++
  315. Routine Description:
  316. Releases resources associated with the values stored
  317. in the value state.
  318. Arguments:
  319. pValState - value state containing values for a logical key
  320. Return Value:
  321. None.
  322. Notes:
  323. --*/
  324. {
  325. DWORD dwValue;
  326. //
  327. // First, free each individual value
  328. //
  329. for (dwValue = 0; dwValue < cMaxValues; dwValue++)
  330. {
  331. //
  332. // Free memory for this value
  333. //
  334. if (ppValueInfo[dwValue]) {
  335. RegClassHeapFree(ppValueInfo[dwValue]);
  336. }
  337. }
  338. //
  339. // Now free the array that held all the values
  340. //
  341. RegClassHeapFree(ppValueInfo);
  342. }
  343. NTSTATUS ValStateInitialize(
  344. ValueState** ppValState,
  345. HKEY hKey)
  346. /*++
  347. Routine Description:
  348. Initializes a value state
  349. Arguments:
  350. pValState - value state containing values for a logical key
  351. hKey - logical key whose state this value state will represent
  352. Return Value:
  353. STATUS_SUCCESS for success, error code otherwise.
  354. Notes:
  355. --*/
  356. {
  357. NTSTATUS Status;
  358. ValueState* pValState;
  359. HKEY hkUser;
  360. HKEY hkMachine;
  361. //
  362. // Initialize conditionally freed resources
  363. //
  364. hkUser = NULL;
  365. hkMachine = NULL;
  366. pValState = NULL;
  367. //
  368. // Get the user and machine keys
  369. //
  370. Status = BaseRegGetUserAndMachineClass(
  371. NULL,
  372. hKey,
  373. MAXIMUM_ALLOWED,
  374. &hkMachine,
  375. &hkUser);
  376. if (NT_SUCCESS(Status)) {
  377. ASSERT(hkUser || hkMachine);
  378. //
  379. // We only need to create a state if there are
  380. // two keys -- if only one exists, we don't
  381. // need to do merging
  382. //
  383. if (!hkUser || !hkMachine) {
  384. *ppValState = NULL;
  385. return STATUS_SUCCESS;
  386. }
  387. //
  388. // Get memory for the value state
  389. //
  390. pValState = RegClassHeapAlloc( sizeof(*pValState) +
  391. sizeof(DWORD) * DEFAULT_VALUESTATE_SUBKEY_ALLOC );
  392. //
  393. // Be sure to release acquired resources on failure
  394. //
  395. if (!pValState) {
  396. if (hkUser != hKey) {
  397. NtClose(hkUser);
  398. } else {
  399. NtClose(hkMachine);
  400. }
  401. return STATUS_NO_MEMORY;
  402. }
  403. RtlZeroMemory(pValState, sizeof(*pValState));
  404. pValState->hkUser = hkUser;
  405. pValState->hkMachine = hkMachine;
  406. pValState->hkLogical = hKey;
  407. pValState->fIgnoreResetOnRetry = TRUE;
  408. //
  409. // Now update the state to reflect the current registry
  410. //
  411. Status = ValStateUpdate(pValState);
  412. }
  413. //
  414. // On success, set our out param
  415. //
  416. if (NT_SUCCESS(Status)) {
  417. *ppValState = pValState;
  418. } else {
  419. if (pValState) {
  420. ValStateRelease(pValState);
  421. }
  422. }
  423. return Status;
  424. }
  425. BOOL ValStateAddValueToSortedValues(
  426. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo,
  427. LONG lNewValue)
  428. /*++
  429. Routine Description:
  430. Inserts a retrieved value into the sorted list
  431. of values in a value state
  432. Arguments:
  433. pValState - value state containing values for a logical key
  434. lNewValue - index of newly added value in the sorted list --
  435. this value needs to be moved elsewhere in the list to maintain
  436. the sorted nature of the list
  437. Return Value:
  438. TRUE if the state was added, FALSE if not.
  439. Notes:
  440. --*/
  441. {
  442. PKEY_VALUE_BASIC_INFORMATION pNewValue;
  443. LONG lFinalSpot;
  444. LONG lCurrent;
  445. UNICODE_STRING NewKeyName;
  446. lFinalSpot = 0;
  447. pNewValue = ppValueInfo[lNewValue];
  448. NewKeyName.Buffer = pNewValue->Name;
  449. NewKeyName.Length = (USHORT) pNewValue->NameLength;
  450. for (lCurrent = lNewValue - 1; lCurrent >= 0; lCurrent--)
  451. {
  452. UNICODE_STRING CurrentValueName;
  453. PKEY_VALUE_BASIC_INFORMATION pCurrentValue;
  454. LONG lCompareResult;
  455. pCurrentValue = ppValueInfo[lCurrent];
  456. CurrentValueName.Buffer = pCurrentValue->Name;
  457. CurrentValueName.Length = (USHORT) pCurrentValue->NameLength;
  458. lCompareResult = RtlCompareUnicodeString(
  459. &NewKeyName,
  460. &CurrentValueName,
  461. TRUE);
  462. if (lCompareResult < 0) {
  463. continue;
  464. } else if (0 == lCompareResult) {
  465. //
  466. // If it's a duplicate, don't add it
  467. //
  468. return FALSE;
  469. } else {
  470. lFinalSpot = lCurrent + 1;
  471. break;
  472. }
  473. }
  474. //
  475. // Now we know the final spot, add the value
  476. //
  477. //
  478. // Move everything up to make room for the new value
  479. //
  480. for (lCurrent = lNewValue - 1; lCurrent >= lFinalSpot; lCurrent--)
  481. {
  482. //
  483. // Move the current value up one
  484. //
  485. ppValueInfo[lCurrent + 1] = ppValueInfo[lCurrent];
  486. }
  487. //
  488. // Copy the value to its final destination
  489. //
  490. ppValueInfo[lFinalSpot] = pNewValue;
  491. //
  492. // This means we've found no duplicate value
  493. // so we add it
  494. //
  495. return TRUE;
  496. }
  497. NTSTATUS KeyStateGetValueState(
  498. HKEY hKey,
  499. ValueState** ppValState)
  500. /*++
  501. Routine Description:
  502. Gets the value state for a particular key
  503. Arguments:
  504. hKey - key whose state we need to retrieve
  505. ppValState - out param pointing to a pointer to the
  506. retrieved state.
  507. Return Value:
  508. STATUS_SUCCESS for success, error code otherwise.
  509. Notes:
  510. ATENTION: Right now, this always creates a new state -- in the future,
  511. we may want to change this to be cached in a table to avoid reconstructing
  512. on every call.
  513. --*/
  514. {
  515. //
  516. // Now build the value state
  517. //
  518. return ValStateInitialize(
  519. ppValState,
  520. hKey);
  521. }
  522. NTSTATUS BaseRegGetClassKeyValueState(
  523. HKEY hKey,
  524. DWORD dwLogicalIndex,
  525. ValueState** ppValState)
  526. /*++
  527. Routine Description:
  528. Gets the value state for a particular key and optimizes
  529. it for a given index
  530. Arguments:
  531. hKey - key whose state we need to retrieve
  532. dwLogicalIndex - hint that helps us to optimize the state for this
  533. index so the caller's use of the state is more efficient
  534. ppValState - out param pointing to a pointer to the
  535. retrieved state.
  536. Return Value:
  537. STATUS_SUCCESS for success, error code otherwise.
  538. Notes:
  539. --*/
  540. {
  541. NTSTATUS Status;
  542. ValueState* pValState;
  543. //
  544. // First retrieve the state for this key
  545. //
  546. Status = KeyStateGetValueState(hKey, &pValState);
  547. if (NT_SUCCESS(Status)) {
  548. //
  549. // Now map the logical index to a physical one
  550. //
  551. Status = ValStateSetPhysicalIndexFromLogical(pValState, dwLogicalIndex);
  552. if (!NT_SUCCESS(Status)) {
  553. ValStateRelease(pValState);
  554. } else {
  555. *ppValState = pValState;
  556. }
  557. }
  558. return Status;
  559. }
  560. NTSTATUS EnumerateValue(
  561. HKEY hKey,
  562. DWORD dwValue,
  563. PKEY_VALUE_BASIC_INFORMATION pSuggestedBuffer,
  564. DWORD dwSuggestedBufferLength,
  565. PKEY_VALUE_BASIC_INFORMATION* ppResult)
  566. /*++
  567. Routine Description:
  568. Retrieves a value for a physical key from the kernel
  569. Arguments:
  570. hKey - physical key for which we're trying to read a value
  571. dwValue - physical index of value to read
  572. pSuggestedBuffer - basinc info buffer to use by default, may not be large enough
  573. dwSuggestedBufferLength - size of suggested buffer
  574. ppResult - pointer to result basic info -- may be allocated by this function if
  575. suggested buffer was insufficient, which means caller will have to free
  576. this if it is not the same as the suggested buffer
  577. Return Value:
  578. STATUS_SUCCESS for success, error code otherwise.
  579. Notes:
  580. --*/
  581. {
  582. NTSTATUS Status;
  583. PKEY_VALUE_BASIC_INFORMATION pKeyValueInformation;
  584. DWORD dwResultLength;
  585. pKeyValueInformation = pSuggestedBuffer;
  586. //
  587. // Query for the necessary information about the supplied value.
  588. //
  589. Status = NtEnumerateValueKey( hKey,
  590. dwValue,
  591. KeyValueBasicInformation,
  592. pKeyValueInformation,
  593. dwSuggestedBufferLength,
  594. &dwResultLength);
  595. //
  596. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  597. // was not enough room for even the known (i.e. fixed length portion)
  598. // of the structure.
  599. //
  600. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  601. if (ppResult && (STATUS_BUFFER_OVERFLOW == Status)) {
  602. pKeyValueInformation = (PKEY_VALUE_BASIC_INFORMATION) RegClassHeapAlloc(
  603. dwResultLength);
  604. if (!pKeyValueInformation) {
  605. return STATUS_NO_MEMORY;
  606. }
  607. //
  608. // Query for the necessary information about the supplied value.
  609. //
  610. Status = NtEnumerateValueKey( hKey,
  611. dwValue,
  612. KeyValueBasicInformation,
  613. pKeyValueInformation,
  614. dwResultLength,
  615. &dwResultLength);
  616. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  617. if (!NT_SUCCESS(Status)) {
  618. RegClassHeapFree(pKeyValueInformation);
  619. }
  620. }
  621. if (NT_SUCCESS(Status) && ppResult) {
  622. *ppResult = pKeyValueInformation;
  623. }
  624. return Status;
  625. }
  626. NTSTATUS BaseRegQueryMultipleClassKeyValues(
  627. HKEY hKey,
  628. PRVALENT val_list,
  629. DWORD num_vals,
  630. LPSTR lpvalueBuf,
  631. LPDWORD ldwTotsize,
  632. PULONG ldwRequiredLength)
  633. /*++
  634. Routine Description:
  635. Gets the value state for a particular key and optimizes
  636. it for a given index
  637. Arguments:
  638. hKey - Supplies a handle to the open key. The value entries returned
  639. are contained in the key pointed to by this key handle. Any of
  640. the predefined reserved handles or a previously opened key handle
  641. may be used for hKey.
  642. val_list - Supplies a pointer to an array of RVALENT structures, one for
  643. each value to be queried.
  644. num_vals - Supplies the size in bytes of the val_list array.
  645. lpValueBuf - Returns the data for each value
  646. ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
  647. written into lpValueBuf.
  648. ldwRequiredLength - If lpValueBuf is not large enough to
  649. contain all the data, returns the size of lpValueBuf required
  650. to return all the requested data.
  651. Return Value:
  652. STATUS_SUCCESS for success, error code otherwise.
  653. Notes:
  654. --*/
  655. {
  656. NTSTATUS Status;
  657. HKEY hkUser;
  658. HKEY hkMachine;
  659. HKEY hkQuery;
  660. //
  661. // Initialize conditionally freed resources
  662. //
  663. hkUser = NULL;
  664. hkMachine = NULL;
  665. //
  666. // First, get both user and machine keys
  667. //
  668. Status = BaseRegGetUserAndMachineClass(
  669. NULL,
  670. hKey,
  671. MAXIMUM_ALLOWED,
  672. &hkMachine,
  673. &hkUser);
  674. if (!NT_SUCCESS(Status)) {
  675. return Status;
  676. }
  677. //
  678. // If we have both, we call a routine
  679. // to merge the values
  680. //
  681. if (hkMachine && hkUser) {
  682. Status = BaseRegQueryAndMergeValues(
  683. hkUser,
  684. hkMachine,
  685. val_list,
  686. num_vals,
  687. lpvalueBuf,
  688. ldwTotsize,
  689. ldwRequiredLength);
  690. goto cleanup;
  691. }
  692. //
  693. // We have only one key -- query the one with the
  694. // highest precedence
  695. //
  696. hkQuery = hkUser ? hkUser : hkMachine;
  697. Status = NtQueryMultipleValueKey(hkQuery,
  698. (PKEY_VALUE_ENTRY)val_list,
  699. num_vals,
  700. lpvalueBuf,
  701. ldwTotsize,
  702. ldwRequiredLength);
  703. cleanup:
  704. //
  705. // Close extra kernel object
  706. //
  707. if (hKey != hkUser) {
  708. NtClose(hkUser);
  709. } else {
  710. NtClose(hkMachine);
  711. }
  712. return Status;
  713. }
  714. NTSTATUS BaseRegQueryAndMergeValues(
  715. HKEY hkUser,
  716. HKEY hkMachine,
  717. PRVALENT val_list,
  718. DWORD num_vals,
  719. LPSTR lpvalueBuf,
  720. LPDWORD ldwTotsize,
  721. PULONG ldwRequiredLength)
  722. /*++
  723. Routine Description:
  724. Gets the value state for a particular key and optimizes
  725. it for a given index
  726. Arguments:
  727. hkUser - user key to query for values
  728. hkMachine - machine key to query for values
  729. val_list - Supplies a pointer to an array of RVALENT structures, one for
  730. each value to be queried.
  731. num_vals - Supplies the size in bytes of the val_list array.
  732. lpValueBuf - Returns the data for each value
  733. ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
  734. written into lpValueBuf.
  735. ldwRequiredLength - If lpValueBuf is not large enough to
  736. contain all the data, returns the size of lpValueBuf required
  737. to return all the requested data.
  738. Return Value:
  739. STATUS_SUCCESS for success, error code otherwise.
  740. Notes:
  741. ATTENTION: this is non-atomic, unlike the regular RegQueryMultipleValues
  742. call. In the future, implementing this in the kernel would make this
  743. atomic again.
  744. --*/
  745. {
  746. NTSTATUS Status;
  747. DWORD dwVal;
  748. BOOL fOverflow;
  749. DWORD dwBufferLength;
  750. DWORD dwRequired;
  751. DWORD dwKeyInfoLength;
  752. DWORD dwBufferUsed;
  753. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
  754. //
  755. // Initialize locals
  756. //
  757. dwBufferLength = *ldwTotsize;
  758. dwRequired = 0;
  759. dwBufferUsed = 0;
  760. fOverflow = FALSE;
  761. //
  762. // Validate out params -- we assume that ldwTotsize and
  763. // ldwRequiredLength were given to us by winreg client,
  764. // so they should be safe to read / write from. lpValueBuf
  765. // comes from the caller of the win32 api, so we need to
  766. // validate it -- in previous versions of NT, this parameter
  767. // went straight to the kernel, which did the validation and
  768. // returned an error if it was pointing to inaccessible memory.
  769. // Since we're accessing it here in user mode, we need to do
  770. // our own validation
  771. //
  772. if (IsBadWritePtr( lpvalueBuf, dwBufferLength))
  773. {
  774. return STATUS_ACCESS_VIOLATION;
  775. }
  776. //
  777. // First, we need to allocate enough memory to retrieve
  778. // all the values -- we can't just use lpvalueBuf
  779. // because it doesn't include the overhead of the
  780. // KEY_VALUE_PARTIAL_INFORMATION structure. If we allocate
  781. // for the size of lpvalueBuf + the structure overhead,
  782. // we will always have enough for our queries.
  783. //
  784. dwKeyInfoLength = sizeof(*pKeyInfo) * num_vals + *ldwTotsize;
  785. pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)
  786. RegClassHeapAlloc( dwKeyInfoLength);
  787. if (!pKeyInfo) {
  788. return STATUS_NO_MEMORY;
  789. }
  790. //
  791. // For each value requested by the caller, try
  792. // to retrieve it from user or machine
  793. //
  794. for (dwVal = 0; dwVal < num_vals; dwVal++)
  795. {
  796. DWORD dwResultLength;
  797. //
  798. // Round up the used and required lengths to a ULONG boundary --
  799. // this means that the required size returned to the caller of the win32
  800. // api can be an overestimation, as much as 3 bytes per requested value.
  801. // We could do some work to avoid this, but since the kernel returns a rounded
  802. // up value in dwResultLength, the kernel api is itself overestimating, although
  803. // it only overestimates by at most 3 bytes over all the values. We could avoid
  804. // this by allocating enough memory ahead of time to query the largest value, either
  805. // as one large preallocation or continually allocating and reallocating, but this will
  806. // be slower and / or consume more memory
  807. //
  808. dwBufferUsed = (dwBufferUsed + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1);
  809. dwRequired = (dwRequired + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1);
  810. //
  811. // Query the user key first since it has highest precedence
  812. //
  813. Status = NtQueryValueKey(
  814. hkUser,
  815. val_list[dwVal].rv_valuename,
  816. KeyValuePartialInformation,
  817. pKeyInfo,
  818. dwKeyInfoLength,
  819. &dwResultLength);
  820. //
  821. // Check for errors -- if the value didn't exist, we'll look
  822. // in machine -- for buffer overflow, we'll proceed as if
  823. // this succeeded so that we can calculate the required
  824. // buffer size
  825. //
  826. if (!NT_SUCCESS(Status) &&
  827. (STATUS_BUFFER_OVERFLOW != Status)) {
  828. if (STATUS_OBJECT_NAME_NOT_FOUND != Status) {
  829. goto cleanup;
  830. }
  831. //
  832. // If there is no user value, query the machine key
  833. //
  834. Status = NtQueryValueKey(
  835. hkMachine,
  836. val_list[dwVal].rv_valuename,
  837. KeyValuePartialInformation,
  838. pKeyInfo,
  839. dwKeyInfoLength,
  840. &dwResultLength);
  841. //
  842. // Similar error handling to above -- if we don't have enough
  843. // buffer, pretend we've succeeded so we can calc the required size
  844. //
  845. if (!NT_SUCCESS(Status) &&
  846. (STATUS_BUFFER_OVERFLOW != Status)) {
  847. goto cleanup;
  848. }
  849. }
  850. ASSERT(NT_SUCCESS(Status) || (STATUS_BUFFER_OVERFLOW == Status));
  851. if (NT_SUCCESS(Status)) {
  852. dwResultLength = pKeyInfo->DataLength;
  853. }
  854. //
  855. // Check for buffer overflow
  856. //
  857. if ( ( (dwBufferUsed + pKeyInfo->DataLength) <= dwBufferLength) && !fOverflow) {
  858. ASSERT(NT_SUCCESS(Status));
  859. //
  860. // Copy the data to the fixed part of the client's structure
  861. //
  862. val_list[dwVal].rv_valuelen = dwResultLength;
  863. val_list[dwVal].rv_valueptr = dwRequired;
  864. val_list[dwVal].rv_type = pKeyInfo->Type;
  865. //
  866. // We didn't overflow, so we still have enough room to copy
  867. // the latest value
  868. //
  869. RtlCopyMemory(
  870. (BYTE*)lpvalueBuf + val_list[dwVal].rv_valueptr,
  871. &(pKeyInfo->Data),
  872. dwResultLength);
  873. dwBufferUsed += pKeyInfo->DataLength;
  874. } else {
  875. //
  876. // We're out of buffer -- set this flag to
  877. // signal this state
  878. //
  879. fOverflow = TRUE;
  880. }
  881. //
  882. // Update our required length with the size
  883. // of the data from the current value
  884. //
  885. dwRequired += dwResultLength;
  886. }
  887. //
  888. // At this point, we've succeeded in the sense that
  889. // we've copied all the data or we couldn't due to
  890. // insufficient buffer but we were able to calculate
  891. // the required size
  892. //
  893. Status = STATUS_SUCCESS;
  894. cleanup:
  895. //
  896. // Free the allocated memory
  897. //
  898. RegClassHeapFree(pKeyInfo);
  899. //
  900. // If we succeeded, this means we've either copied
  901. // the data or overflowed and copied the size -- handle
  902. // both below
  903. //
  904. if (NT_SUCCESS(Status)) {
  905. //
  906. // Always set this so the caller knows how much
  907. // was copied or needs to be allocated
  908. //
  909. *ldwRequiredLength = dwRequired;
  910. //
  911. // Return the appropriate error if we overflowed
  912. //
  913. if (fOverflow) {
  914. return STATUS_BUFFER_OVERFLOW;
  915. }
  916. //
  917. // Setting this, although winreg client actually
  918. // ignores this quantity
  919. //
  920. *ldwTotsize = dwBufferUsed;
  921. }
  922. return Status;
  923. }
  924. #endif LOCAL