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.

519 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Regqval.c
  5. Abstract:
  6. This module contains the server side implementation for the Win32
  7. Registry query value API. That is:
  8. - BaseRegQueryValue
  9. - BaseRegQueryMultipleValues
  10. Author:
  11. David J. Gilman (davegi) 27-Nov-1991
  12. Notes:
  13. See the Notes in Regkey.c.
  14. --*/
  15. #include <rpc.h>
  16. #include "regrpc.h"
  17. #include "localreg.h"
  18. #include "regclass.h"
  19. #include "regvcls.h"
  20. #define DEFAULT_VALUE_SIZE 128
  21. #define DEFAULT_VALUE_NAME_SIZE 64
  22. error_status_t
  23. BaseRegQueryValue(
  24. IN HKEY hKey,
  25. IN PUNICODE_STRING lpValueName,
  26. OUT LPDWORD lpType OPTIONAL,
  27. OUT LPBYTE lpData OPTIONAL,
  28. OUT LPDWORD lpcbData OPTIONAL,
  29. IN OUT LPDWORD lpcbLen OPTIONAL
  30. )
  31. /*++
  32. Routine Description:
  33. For an open key, given the ID of the value to query, return
  34. the type, and value.
  35. Arguments:
  36. hKey - Supplies a handle to the open key. The value entries returned
  37. are contained in the key pointed to by this key handle. Any of the
  38. predefined reserved handles or a previously opened key handle may be
  39. used for hKey.
  40. lpValueName - Supplies a pointer to the name of the value.
  41. lpType - If present, supplies a pointer to variable to receive the
  42. type code of value entry.
  43. lpData -If present, supplies a pointer to a buffer to receive the
  44. data of the value entry.
  45. lpcbData - Supplies a pointer to a variable which on input contains
  46. the size of the buffer lpData points to. On output, the variable will
  47. receive the number of bytes returned in lpData. It must be supplied
  48. if lpData is, it is ignored otherwise.
  49. lpcbLen - Return the number of bytes to transmit to the client (used
  50. by RPC).
  51. Return Value:
  52. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  53. --*/
  54. {
  55. NTSTATUS Status;
  56. ULONG BufferLength;
  57. KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
  58. PVOID KeyValueInformation;
  59. ULONG ResultLength;
  60. HKEY hkQueryKey;
  61. BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_PARTIAL_INFORMATION ) +
  62. DEFAULT_VALUE_SIZE ];
  63. #ifdef LOCAL
  64. HKEY hkUserClasses;
  65. HKEY hkMachineClasses;
  66. hkUserClasses = NULL;
  67. hkMachineClasses = NULL;
  68. #endif LOCAL
  69. hkQueryKey = hKey;
  70. //
  71. // If the client gave us a bogus size, patch it.
  72. //
  73. if ( ARGUMENT_PRESENT( lpcbData ) && !ARGUMENT_PRESENT( lpData ) ) {
  74. *lpcbData = 0;
  75. }
  76. //
  77. // Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA.
  78. //
  79. if(( hKey == HKEY_PERFORMANCE_DATA ) ||
  80. ( hKey == HKEY_PERFORMANCE_TEXT ) ||
  81. ( hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  82. error_status_t Error;
  83. //
  84. // Impersonate the client.
  85. //
  86. RPC_IMPERSONATE_CLIENT( NULL );
  87. Error = (error_status_t)PerfRegQueryValue (
  88. hKey,
  89. lpValueName,
  90. NULL,
  91. lpType,
  92. lpData,
  93. lpcbData,
  94. lpcbLen
  95. );
  96. RPC_REVERT_TO_SELF();
  97. return(Error);
  98. }
  99. ASSERT( IsPredefinedRegistryHandle( hKey ) == FALSE );
  100. //
  101. // Subtract the NULL from the Length. This was added on
  102. // the client side so that RPC would transmit it.
  103. //
  104. if ( lpValueName->Length > 0 ) {
  105. lpValueName->Length -= sizeof( UNICODE_NULL );
  106. }
  107. //
  108. // First we assume that the information we want will fit on
  109. // PrivateKeyValueInformattion
  110. //
  111. KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?
  112. KeyValuePartialInformation :
  113. KeyValueBasicInformation;
  114. KeyValueInformation = PrivateKeyValueInformation;
  115. BufferLength = sizeof( PrivateKeyValueInformation );
  116. //
  117. // Query for the necessary information about the supplied value. This
  118. // may or may not include the data depending on lpcbData as determined
  119. // above.
  120. //
  121. #ifdef LOCAL
  122. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  123. Status = BaseRegGetUserAndMachineClass(
  124. NULL,
  125. hKey,
  126. MAXIMUM_ALLOWED,
  127. &hkMachineClasses,
  128. &hkUserClasses);
  129. if (!NT_SUCCESS(Status)) {
  130. return (error_status_t) RtlNtStatusToDosError(Status);
  131. }
  132. }
  133. if (hkUserClasses && hkMachineClasses) {
  134. hkQueryKey = hkUserClasses;
  135. }
  136. for (;;) {
  137. #endif
  138. Status = NtQueryValueKey( hkQueryKey,
  139. lpValueName,
  140. KeyValueInformationClass,
  141. KeyValueInformation,
  142. BufferLength,
  143. &ResultLength
  144. );
  145. #ifdef LOCAL
  146. //
  147. // If we don't have two classes keys to worry about,
  148. // just continue as we normally would
  149. //
  150. if (!hkUserClasses || !hkMachineClasses) {
  151. break;
  152. }
  153. //
  154. // If we're using machine, then we don't want to repeat
  155. // since machine is the last resort
  156. //
  157. if (hkQueryKey == hkMachineClasses) {
  158. break;
  159. }
  160. //
  161. // If the key doesn't exist in user, then let's try
  162. // again in machine
  163. //
  164. if (STATUS_OBJECT_NAME_NOT_FOUND == Status) {
  165. hkQueryKey = hkMachineClasses;
  166. continue;
  167. }
  168. break;
  169. }
  170. #endif
  171. //
  172. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  173. // was not enough room for even the known (i.e. fixed length portion)
  174. // of the structure.
  175. //
  176. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  177. if( ( Status == STATUS_BUFFER_OVERFLOW ) &&
  178. ( !ARGUMENT_PRESENT( lpData ) ) ) {
  179. //
  180. // STATUS_BUFFER_OVERFLOW means that the API returned all the
  181. // information in the fixed portion of the structure
  182. // KEY_VALUE_BASIC_INFORMATION or KEY_VALUE_PARTIAL_INFORMATION,
  183. // but not the value name or the value data.
  184. //
  185. // If KeyValueInformationClass is equal to KeyValueBasicInformation
  186. // then the API would return the value name. But since we are not
  187. // interested in the value name (it was supplied by the client), we
  188. // can assume that the API succeeded.
  189. //
  190. // If KeyValueInformationClass is equal to KeyValuePartialInformation
  191. // then the API would return the value data. But lpData == NULL
  192. // means that the client is not interested on the value data, but
  193. // just on its size. For this reason, we can also assume that the
  194. // API succeeded.
  195. //
  196. Status = STATUS_SUCCESS;
  197. }
  198. if( Status == STATUS_BUFFER_OVERFLOW ) {
  199. //
  200. // The buffer defined in the stack wasn't big enough to hold
  201. // the Value information.
  202. // If the caller's buffer is big enough to hold the value data
  203. // then allocate a new buffer, and call the NT API again.
  204. //
  205. if( ( ( KeyValueInformationClass == KeyValuePartialInformation ) &&
  206. ( ARGUMENT_PRESENT( lpData ) ) &&
  207. ( *lpcbData >=
  208. (( PKEY_VALUE_PARTIAL_INFORMATION )
  209. KeyValueInformation )->DataLength
  210. )
  211. )
  212. ) {
  213. BufferLength = ResultLength;
  214. KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
  215. BufferLength
  216. );
  217. //
  218. // If the memory allocation fails, return a Registry error.
  219. //
  220. if( ! KeyValueInformation ) {
  221. return ERROR_OUTOFMEMORY;
  222. }
  223. //
  224. // Query for the necessary information about the supplied value.
  225. //
  226. Status = NtQueryValueKey( hkQueryKey,
  227. lpValueName,
  228. KeyValueInformationClass,
  229. KeyValueInformation,
  230. BufferLength,
  231. &ResultLength
  232. );
  233. }
  234. }
  235. #ifdef LOCAL
  236. if (hkUserClasses && hkMachineClasses) {
  237. if (hkUserClasses != hKey) {
  238. NtClose(hkUserClasses);
  239. } else {
  240. NtClose(hkMachineClasses);
  241. }
  242. }
  243. #endif // LOCAL
  244. if( NT_SUCCESS( Status ) &&
  245. ARGUMENT_PRESENT( lpData ) ) {
  246. //
  247. // If requested, copy the value data
  248. //
  249. if( *lpcbData >= (( PKEY_VALUE_PARTIAL_INFORMATION )
  250. KeyValueInformation )->DataLength ) {
  251. RtlMoveMemory( lpData,
  252. (( PKEY_VALUE_PARTIAL_INFORMATION )
  253. KeyValueInformation )->Data,
  254. (( PKEY_VALUE_PARTIAL_INFORMATION )
  255. KeyValueInformation )->DataLength
  256. );
  257. } else {
  258. Status = STATUS_BUFFER_OVERFLOW;
  259. }
  260. }
  261. //
  262. // Certain information is returned on success or in the case of
  263. // NtQueryValueKey returning STATUS_BUFFER_OVERFLOW. This information
  264. // is always available because we always pass the minimum size required for
  265. // the NtQueryValueKey API.
  266. //
  267. if( NT_SUCCESS( Status ) ||
  268. ( Status == STATUS_BUFFER_OVERFLOW ) ) {
  269. if( KeyValueInformationClass == KeyValueBasicInformation ) {
  270. //
  271. // If requested, return the value type.
  272. //
  273. if( ARGUMENT_PRESENT( lpType )) {
  274. *lpType = (( PKEY_VALUE_BASIC_INFORMATION )
  275. KeyValueInformation )->Type;
  276. }
  277. } else {
  278. //
  279. // If requested, return the value type.
  280. //
  281. if( ARGUMENT_PRESENT( lpType )) {
  282. *lpType = (( PKEY_VALUE_PARTIAL_INFORMATION )
  283. KeyValueInformation )->Type;
  284. }
  285. //
  286. // Return the value data size
  287. //
  288. *lpcbData = (( PKEY_VALUE_PARTIAL_INFORMATION )
  289. KeyValueInformation )->DataLength;
  290. }
  291. }
  292. //
  293. // Transmit all of the data back to the client.
  294. //
  295. if( ARGUMENT_PRESENT( lpcbLen ) ) {
  296. if( NT_SUCCESS( Status ) &&
  297. ARGUMENT_PRESENT( lpData ) ) {
  298. *lpcbLen = (( PKEY_VALUE_PARTIAL_INFORMATION )
  299. KeyValueInformation )->DataLength;
  300. } else {
  301. //
  302. // The API failed, so make sure that no data is transmitted back
  303. // to the client. This ensures that the client stub will not
  304. // attempt to unmarshall data that doesn't exist.
  305. //
  306. *lpcbLen = 0;
  307. }
  308. }
  309. //
  310. // If memory was allocated, then free it
  311. //
  312. if( KeyValueInformation != PrivateKeyValueInformation ) {
  313. RtlFreeHeap( RtlProcessHeap( ), 0, KeyValueInformation );
  314. }
  315. return (error_status_t)RtlNtStatusToDosError( Status );
  316. }
  317. error_status_t
  318. BaseRegQueryMultipleValues(
  319. IN HKEY hKey,
  320. IN OUT PRVALENT val_list,
  321. IN DWORD num_vals,
  322. OUT LPSTR lpvalueBuf,
  323. IN OUT LPDWORD ldwTotsize
  324. )
  325. /*++
  326. Routine Description:
  327. For an open key, atomically queries a set of values.
  328. Arguments:
  329. hKey - Supplies a handle to the open key. The value entries returned
  330. are contained in the key pointed to by this key handle. Any of
  331. the predefined reserved handles or a previously opened key handle
  332. may be used for hKey.
  333. val_list - Supplies a pointer to an array of RVALENT structures, one for
  334. each value to be queried.
  335. num_vals - Supplies the size in bytes of the val_list array.
  336. lpValueBuf - Returns the data for each value
  337. ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
  338. written into lpValueBuf. If lpValueBuf is not large enough to
  339. contain all the data, returns the size of lpValueBuf required
  340. to return all the requested data.
  341. Return Value:
  342. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  343. --*/
  344. {
  345. NTSTATUS Status;
  346. ULONG RequiredLength;
  347. ULONG i;
  348. //
  349. // Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA.
  350. //
  351. if(( hKey == HKEY_PERFORMANCE_DATA ) ||
  352. ( hKey == HKEY_PERFORMANCE_TEXT ) ||
  353. ( hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  354. return((error_status_t)ERROR_CALL_NOT_IMPLEMENTED);
  355. }
  356. //
  357. // Subtract the NULLs from the Length. This was added on
  358. // the client side so that RPC would transmit it.
  359. //
  360. for (i=0; i<num_vals; i++) {
  361. if (val_list[i].rv_valuename->Length > 0) {
  362. val_list[i].rv_valuename->Length -= sizeof( UNICODE_NULL );
  363. }
  364. }
  365. #ifdef LOCAL
  366. //
  367. // For class keys in hkcr, we need to merge the data
  368. //
  369. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  370. Status = BaseRegQueryMultipleClassKeyValues(
  371. hKey,
  372. val_list,
  373. num_vals,
  374. lpvalueBuf,
  375. ldwTotsize,
  376. &RequiredLength);
  377. } else {
  378. #endif // LOCAL
  379. Status = NtQueryMultipleValueKey(hKey,
  380. (PKEY_VALUE_ENTRY)val_list,
  381. num_vals,
  382. lpvalueBuf,
  383. ldwTotsize,
  384. &RequiredLength);
  385. #ifdef LOCAL
  386. }
  387. #endif // LOCAL
  388. if (Status == STATUS_BUFFER_OVERFLOW) {
  389. *ldwTotsize = RequiredLength;
  390. } else if (!NT_SUCCESS(Status)) {
  391. //
  392. // The API failed, so make sure that no data is transmitted back
  393. // to the client. This ensures that the client stub will not
  394. // attempt to unmarshall data that doesn't exist.
  395. //
  396. *ldwTotsize = 0;
  397. }
  398. return(error_status_t)RtlNtStatusToDosError(Status);
  399. }