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.

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