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.

518 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Regeval.c
  5. Abstract:
  6. This module contains the server side implementation for the Win32
  7. Registry API to enumerate values. That is:
  8. - BaseRegEnumValue
  9. Author:
  10. David J. Gilman (davegi) 23-Dec-1991
  11. Notes:
  12. See the Notes in Regkey.c.
  13. --*/
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "localreg.h"
  17. #include "regclass.h"
  18. #include "regvcls.h"
  19. #define DEFAULT_VALUE_SIZE 128
  20. #define DEFAULT_VALUE_NAME_SIZE 64
  21. error_status_t
  22. BaseRegEnumValue(
  23. IN HKEY hKey,
  24. IN DWORD dwIndex,
  25. OUT PUNICODE_STRING lpValueName,
  26. OUT LPDWORD lpType OPTIONAL,
  27. OUT LPBYTE lpData OPTIONAL,
  28. IN OUT LPDWORD lpcbData OPTIONAL,
  29. IN OUT LPDWORD lpcbLen OPTIONAL
  30. )
  31. /*++
  32. Routine Description:
  33. Used to enumerate the ValueNames of an open key. This function copies
  34. the dwIndex-th ValueName of hKey. This function is guaranteed to
  35. operate correctly only if dwIndex starts at 0 and is incremented on
  36. successive calls without intervening calls to other registration APIs
  37. that will change the key. The ValueName (only the ValueName, not the
  38. full path) is copied to lpBuffer. The size of lpBuffer is specified
  39. by dwBufferSize.
  40. Arguments:
  41. hKey - A handle to the open key. The value entries returned are
  42. contained in the key pointed to by this key handle. Any of the
  43. predefined reserved handles or a previously opened key handle may be
  44. used for hKey.
  45. dwIndex - The index of the ValueName to return. Note that this is for
  46. convenience, ValueNames are not ordered (a new ValueName has an
  47. arbitrary index). Indexes start at 0.
  48. lpValueName - Provides a pointer to a buffer to receive the name of
  49. the value (it's Id)
  50. lpType - If present, supplies pointer to variable to receive the type
  51. code of value entry.
  52. lpData - If present, provides a pointer to a buffer to receive the
  53. data of the value entry.
  54. lpcbData - Must be present if lpDatais. Provides pointer to a
  55. variable which on input contains the size of the buffer lpDatapoints
  56. to. On output, the variable will receive the number of bytes returned
  57. in lpData.
  58. lpcbLen - Return the number of bytes to transmit to the client (used
  59. by RPC).
  60. Return Value:
  61. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  62. Notes:
  63. hKey must have been opened for KEY_QUERY_VALUE access.
  64. --*/
  65. {
  66. NTSTATUS Status;
  67. ULONG BufferLength;
  68. KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
  69. PVOID KeyValueInformation;
  70. ULONG ResultLength;
  71. BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_FULL_INFORMATION ) +
  72. DEFAULT_VALUE_NAME_SIZE +
  73. sizeof(UNICODE_NULL) +
  74. DEFAULT_VALUE_SIZE +
  75. sizeof(UNICODE_NULL) ];
  76. HKEY hkEnum;
  77. #ifdef LOCAL
  78. ValueState* pValState;
  79. pValState = NULL;
  80. #endif // LOCAL
  81. hkEnum = hKey;
  82. //
  83. // If the client gave us a bogus size, patch it.
  84. //
  85. if ( ARGUMENT_PRESENT( lpcbData ) && !ARGUMENT_PRESENT( lpData ) ) {
  86. *lpcbData = 0;
  87. }
  88. if( (lpValueName == NULL) || (lpValueName->Buffer == NULL) ) {
  89. //
  90. // malicious RPC attack
  91. //
  92. return(ERROR_INVALID_PARAMETER);
  93. }
  94. //
  95. // Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA.
  96. //
  97. if(( hKey == HKEY_PERFORMANCE_DATA ) ||
  98. ( hKey == HKEY_PERFORMANCE_TEXT ) ||
  99. ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {
  100. return (error_status_t)PerfRegEnumValue (
  101. hKey,
  102. dwIndex,
  103. lpValueName,
  104. NULL,
  105. lpType,
  106. lpData,
  107. lpcbData,
  108. lpcbLen
  109. );
  110. }
  111. #ifdef LOCAL
  112. //
  113. // If we are in HKEY_CLASSES_ROOT, then we need to remap
  114. // the key / index pair to take into account merging
  115. //
  116. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  117. //
  118. // Find a key state for this key
  119. //
  120. Status = BaseRegGetClassKeyValueState(
  121. hKey,
  122. dwIndex,
  123. &pValState);
  124. if (!NT_SUCCESS(Status)) {
  125. return (error_status_t)RtlNtStatusToDosError(Status);
  126. }
  127. //
  128. // Now remap to the appropriate key / index
  129. //
  130. ValStateGetPhysicalIndexFromLogical(
  131. pValState,
  132. hKey,
  133. dwIndex,
  134. &hkEnum,
  135. &dwIndex);
  136. }
  137. #endif // LOCAL
  138. //
  139. // First we assume that the information we want will fit on
  140. // PrivateKeyValueInformattion
  141. //
  142. KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?
  143. KeyValueFullInformation :
  144. KeyValueBasicInformation;
  145. KeyValueInformation = PrivateKeyValueInformation;
  146. BufferLength = sizeof( PrivateKeyValueInformation );
  147. //
  148. // Query for the necessary information about the supplied value.
  149. //
  150. Status = NtEnumerateValueKey( hkEnum,
  151. dwIndex,
  152. KeyValueInformationClass,
  153. KeyValueInformation,
  154. BufferLength,
  155. &ResultLength
  156. );
  157. //
  158. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  159. // was not enough room for even the known (i.e. fixed length portion)
  160. // of the structure.
  161. //
  162. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  163. if( Status == STATUS_BUFFER_OVERFLOW ) {
  164. //
  165. // The buffer defined in the stack wasn't big enough to hold
  166. // the Value information.
  167. // If the caller's buffer are big enough to hold the value name
  168. // and value data, then allocate a new buffer, and call the
  169. // NT API again.
  170. //
  171. if( ( ( KeyValueInformationClass == KeyValueBasicInformation ) &&
  172. ( (ULONG)(lpValueName->MaximumLength) >=
  173. (( PKEY_VALUE_BASIC_INFORMATION )
  174. KeyValueInformation )->NameLength + sizeof(UNICODE_NULL)
  175. )
  176. ) ||
  177. ( ( KeyValueInformationClass == KeyValueFullInformation ) &&
  178. ( (ULONG)(lpValueName->MaximumLength) >=
  179. (( PKEY_VALUE_FULL_INFORMATION )
  180. KeyValueInformation )->NameLength + sizeof(UNICODE_NULL)
  181. ) &&
  182. ( !ARGUMENT_PRESENT( lpData ) ||
  183. ( ARGUMENT_PRESENT( lpData ) &&
  184. ARGUMENT_PRESENT( lpcbData ) &&
  185. ( *lpcbData >= (( PKEY_VALUE_FULL_INFORMATION )
  186. KeyValueInformation )->DataLength
  187. )
  188. )
  189. )
  190. )
  191. ) {
  192. BufferLength = ResultLength;
  193. KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
  194. BufferLength
  195. );
  196. //
  197. // If the memory allocation fails, return a Registry error.
  198. //
  199. if( ! KeyValueInformation ) {
  200. #ifdef LOCAL
  201. ValStateRelease(pValState);
  202. #endif // LOCAL
  203. return ERROR_OUTOFMEMORY;
  204. }
  205. //
  206. // Query for the necessary information about the supplied value. This
  207. // may or may not include the data depending on lpcbData as determined
  208. // above.
  209. //
  210. Status = NtEnumerateValueKey( hkEnum,
  211. dwIndex,
  212. KeyValueInformationClass,
  213. KeyValueInformation,
  214. BufferLength,
  215. &ResultLength
  216. );
  217. }
  218. }
  219. #ifdef LOCAL
  220. ValStateRelease(pValState);
  221. #endif // LOCAL
  222. //
  223. // If the API succeeded, try to copy the value name to the client's buffer
  224. //
  225. if( NT_SUCCESS( Status ) ) {
  226. //
  227. // Copy value name
  228. //
  229. if( KeyValueInformationClass == KeyValueBasicInformation ) {
  230. //
  231. // Return the name length and the name of the value.
  232. // Note that the NUL byte is included so that RPC copies the
  233. // correct number of bytes. It is decremented on the client
  234. // side.
  235. //
  236. if( (ULONG)(lpValueName->MaximumLength) >=
  237. (( PKEY_VALUE_BASIC_INFORMATION )
  238. KeyValueInformation )->NameLength + sizeof( UNICODE_NULL )) {
  239. //
  240. // If client's buffer is big enough for the name,
  241. // copy the value name and NUL terminate it
  242. //
  243. lpValueName->Length = ( USHORT )
  244. (( PKEY_VALUE_BASIC_INFORMATION )
  245. KeyValueInformation )->NameLength;
  246. RtlMoveMemory( lpValueName->Buffer,
  247. (( PKEY_VALUE_BASIC_INFORMATION )
  248. KeyValueInformation )->Name,
  249. lpValueName->Length
  250. );
  251. lpValueName->Buffer[ lpValueName->Length >> 1 ] = UNICODE_NULL;
  252. //
  253. // Value name length must include size of UNICODE_NULL.
  254. // It will be decremented in the client side
  255. //
  256. lpValueName->Length += sizeof( UNICODE_NULL );
  257. } else {
  258. //
  259. // If the client's buffer for the value name is not big
  260. // enough, then set status to STATUS_BUFFER_OVERFLOW.
  261. //
  262. // Note that in the remote case, RPC will transmit garbage
  263. // in the buffer back to the client.
  264. // We cannot set the buffer to prevent this transmission,
  265. // because in the local case we would be destroying the
  266. // buffer in the &NtCurrectTeb->StaticUnicodeString.
  267. //
  268. Status = STATUS_BUFFER_OVERFLOW;
  269. }
  270. } else {
  271. //
  272. // Here if KeyValueInformation == KeyValueFullInformation
  273. //
  274. // Return the name length and the name of the value.
  275. // Note that the NUL byte is included so that RPC copies the
  276. // correct number of bytes. It is decremented on the client
  277. // side.
  278. //
  279. if( (ULONG)(lpValueName->MaximumLength) >=
  280. (( PKEY_VALUE_FULL_INFORMATION )
  281. KeyValueInformation )->NameLength + sizeof( UNICODE_NULL )) {
  282. //
  283. // If client's buffer is big enough for the name,
  284. // copy the value name and NUL terminate it
  285. //
  286. lpValueName->Length = ( USHORT )
  287. (( PKEY_VALUE_FULL_INFORMATION )
  288. KeyValueInformation )->NameLength;
  289. RtlMoveMemory( lpValueName->Buffer,
  290. (( PKEY_VALUE_FULL_INFORMATION )
  291. KeyValueInformation )->Name,
  292. lpValueName->Length
  293. );
  294. lpValueName->Buffer[ lpValueName->Length >> 1 ] = UNICODE_NULL;
  295. //
  296. // Value name length must include size of UNICODE_NULL.
  297. // It will be decremented in the client side
  298. //
  299. lpValueName->Length += sizeof( UNICODE_NULL );
  300. } else {
  301. //
  302. // If the client's buffer for the value name is not big
  303. // enough, then set status to STATUS_BUFFER_OVERFLOW.
  304. //
  305. // Note that in the remote case, RPC will transmit garbage
  306. // in the buffer back to the client.
  307. // We cannot set the buffer to prevent this transmission,
  308. // because in the local case we would be destroying the
  309. // buffer in the &NtCurrectTeb->StaticUnicodeString.
  310. //
  311. Status = STATUS_BUFFER_OVERFLOW;
  312. }
  313. }
  314. }
  315. if( NT_SUCCESS( Status ) &&
  316. ARGUMENT_PRESENT( lpData ) ) {
  317. //
  318. // If we were able to copy the value name to the client's buffer
  319. // and the value data is also requested, then try to copy it
  320. // to the client's buffer
  321. //
  322. if( *lpcbData >= (( PKEY_VALUE_FULL_INFORMATION )
  323. KeyValueInformation )->DataLength ) {
  324. //
  325. // If the buffer is big enough to hold the data, copy the data
  326. //
  327. RtlMoveMemory( lpData,
  328. ( PBYTE ) KeyValueInformation
  329. + (( PKEY_VALUE_FULL_INFORMATION )
  330. KeyValueInformation )->DataOffset,
  331. (( PKEY_VALUE_FULL_INFORMATION )
  332. KeyValueInformation )->DataLength
  333. );
  334. } else {
  335. //
  336. // If buffer is not big enough to hold the data, then return
  337. // STATUS_BUFFER_OVERFLOW.
  338. //
  339. // Note that in the remote case, RPC will transmit garbage
  340. // in the buffer back to the client.
  341. // We cannot set the buffer to prevent this transmission,
  342. // because in the local case we would be destroying the
  343. // buffer in the &NtCurrectTeb->StaticUnicodeString.
  344. //
  345. Status = STATUS_BUFFER_OVERFLOW;
  346. }
  347. }
  348. //
  349. // Certain information is returned on success or in the case of
  350. // NtEnumerateValueKey returning STATUS_BUFFER_OVERFLOW. This information
  351. // is always available because we always pass the minimum size required for
  352. // the NtEnumerateValueKey API.
  353. //
  354. if( NT_SUCCESS( Status ) ||
  355. ( Status == STATUS_BUFFER_OVERFLOW ) ) {
  356. if( KeyValueInformationClass == KeyValueBasicInformation ) {
  357. //
  358. // If requested, return the value type.
  359. //
  360. if( ARGUMENT_PRESENT( lpType )) {
  361. *lpType = (( PKEY_VALUE_BASIC_INFORMATION )
  362. KeyValueInformation )->Type;
  363. }
  364. // lpValueName->Length
  365. // = ( USHORT ) ((( PKEY_VALUE_BASIC_INFORMATION )
  366. // KeyValueInformation )->NameLength + sizeof( UNICODE_NULL ) );
  367. } else {
  368. //
  369. // Here if KeyValueInformationClass == KeyValueFullInformation
  370. //
  371. //
  372. // If requested, return the value type.
  373. //
  374. if( ARGUMENT_PRESENT( lpType )) {
  375. *lpType = (( PKEY_VALUE_FULL_INFORMATION )
  376. KeyValueInformation )->Type;
  377. }
  378. // lpValueName->Length
  379. // = ( USHORT ) ((( PKEY_VALUE_FULL_INFORMATION )
  380. // KeyValueInformation )->NameLength + sizeof( UNICODE_NULL ) );
  381. *lpcbData = (( PKEY_VALUE_FULL_INFORMATION )
  382. KeyValueInformation )->DataLength;
  383. }
  384. }
  385. //
  386. // Transmit all of the value data back to the client.
  387. //
  388. if( NT_SUCCESS( Status ) ) {
  389. if( ARGUMENT_PRESENT( lpcbLen ) &&
  390. ARGUMENT_PRESENT( lpcbData ) ) {
  391. *lpcbLen = *lpcbData;
  392. }
  393. } else {
  394. //
  395. // If something failed, don't transmit any data back to the client
  396. //
  397. if( ARGUMENT_PRESENT( lpcbLen ) ) {
  398. *lpcbLen = 0;
  399. }
  400. }
  401. //
  402. // Free memory if it was allocated
  403. //
  404. if( KeyValueInformation != PrivateKeyValueInformation ) {
  405. RtlFreeHeap( RtlProcessHeap( ), 0, KeyValueInformation );
  406. }
  407. return (error_status_t)RtlNtStatusToDosError( Status );
  408. }
  409.