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.

542 lines
19 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. regqmval.c
  5. Abstract:
  6. This module contains the client side wrappers for the Win32 Registry
  7. query multiple values APIs:
  8. - RegQueryMultipleValuesA
  9. - RegQueryMultipleValuesW
  10. Author:
  11. John Vert (jvert) 15-Jun-1995
  12. Revision History:
  13. --*/
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "client.h"
  17. WINADVAPI
  18. LONG
  19. APIENTRY
  20. RegQueryMultipleValuesA (
  21. HKEY hKey,
  22. PVALENTA val_list,
  23. DWORD num_vals,
  24. LPSTR lpValueBuf,
  25. LPDWORD ldwTotsize
  26. )
  27. /*++
  28. Routine Description:
  29. The RegQueryMultipleValues function retrieves a list of
  30. data type/data pairs for a list of value names associated
  31. with an open registry key.
  32. Parameters:
  33. hKey
  34. Identifies a currently open key or any of the pre-defined reserved handle values:
  35. HKEY_CLASSES_ROOT
  36. HEY_CURRENT_USER
  37. HKEY_LOCAL_MACHINE
  38. HKEY_USERS
  39. valList
  40. Points to an array of structures describing one or more value entries. This
  41. contains the value names of the values to be queried. Refer to Appendix A for a
  42. description of VALUE_ENTRY structure.
  43. num_vals
  44. Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
  45. fractional extra space pointed to by valList is ignored.
  46. lpValueBuf
  47. The output buffer for returning value information (value names and value data). Data
  48. is DWORD aligned with pads inserted as necessary.
  49. ldwTotsize
  50. The total size of the output buffer pointed to by lpvalueBuf. On output ldwTotsize
  51. contains the number of bytes used including pads. If lpValueBuf was too short, then on
  52. output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
  53. filled up to the size specified by ldwTotsize on input.
  54. Return value:
  55. If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
  56. of the error value which can be returned by RegQueryValueEx. In addition, if
  57. either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
  58. If the function is unable to instantiate/access the provider of the
  59. dynamic key, it will return ERROR_CANTREAD. If the total length of the
  60. requested data (valListLength + ldwTotSize) is more than the system limit of one
  61. megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
  62. megabyte of data is returned.
  63. --*/
  64. {
  65. NTSTATUS Status;
  66. PRVALENT Values;
  67. PUNICODE_STRING Names;
  68. LONG Error;
  69. ULONG i;
  70. ULONG DataLength;
  71. ULONG InputLength;
  72. LPDWORD pTotalSize;
  73. DWORD TotalSize;
  74. ANSI_STRING AnsiString;
  75. LPSTR NewValueBuf = NULL;
  76. DWORD DataOffset;
  77. ULONG AnsiLength;
  78. HKEY TempHandle = NULL;
  79. DWORD RequiredSize;
  80. hKey = MapPredefinedHandle(hKey, &TempHandle);
  81. if (hKey == NULL) {
  82. Error = ERROR_INVALID_HANDLE;
  83. goto ExitCleanup;
  84. }
  85. //
  86. // Allocate an array of RVALENTs to describe the input value names
  87. //
  88. Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
  89. if (Values == NULL) {
  90. Error = ERROR_OUTOFMEMORY;
  91. goto ExitCleanup;
  92. }
  93. ZeroMemory(Values, sizeof(RVALENT)*num_vals);
  94. //
  95. // Allocate an array of UNICODE_STRINGs to contain the input names
  96. //
  97. Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
  98. if (Names == NULL) {
  99. Error = ERROR_OUTOFMEMORY;
  100. RtlFreeHeap(RtlProcessHeap(),0,Values);
  101. goto ExitCleanup;
  102. }
  103. ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
  104. //
  105. // Convert the value names to UNICODE_STRINGs
  106. //
  107. for (i=0; i<num_vals; i++) {
  108. RtlInitAnsiString(&AnsiString, val_list[i].ve_valuename);
  109. Status = RtlAnsiStringToUnicodeString(&Names[i], &AnsiString, TRUE);
  110. if (!NT_SUCCESS(Status)) {
  111. Error = RtlNtStatusToDosError( Status );
  112. goto Cleanup;
  113. }
  114. //
  115. // Add the terminating NULL to the Length so that RPC transmits
  116. // it.
  117. //
  118. Names[i].Length += sizeof( UNICODE_NULL );
  119. Values[i].rv_valuename = &Names[i];
  120. }
  121. //
  122. // Allocate a data buffer twice the size of the input buffer
  123. // so that any Unicode value data will fit before it is converted
  124. // to Ansi.
  125. //
  126. if ((ldwTotsize == NULL) || (*ldwTotsize == 0)) {
  127. TotalSize = 0;
  128. } else {
  129. TotalSize = *ldwTotsize * sizeof(WCHAR);
  130. NewValueBuf = RtlAllocateHeap(RtlProcessHeap(),0,TotalSize);
  131. if (NewValueBuf == NULL) {
  132. Error = ERROR_OUTOFMEMORY;
  133. goto Cleanup;
  134. }
  135. }
  136. pTotalSize = &TotalSize;
  137. //
  138. // Call the Base API, passing it the supplied parameters and the
  139. // counted Unicode strings.
  140. //
  141. if (IsLocalHandle(hKey)) {
  142. //
  143. // try new method first
  144. //
  145. RpcTryExcept {
  146. Error = (LONG)LocalBaseRegQueryMultipleValues2(hKey,
  147. Values,
  148. num_vals,
  149. NewValueBuf,
  150. pTotalSize,
  151. &RequiredSize);
  152. *pTotalSize = RequiredSize;
  153. }
  154. RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  155. Error = RpcExceptionCode();
  156. if( Error == RPC_S_PROCNUM_OUT_OF_RANGE) {
  157. //
  158. // old server
  159. //
  160. //DbgPrint("WINREG: RPC_S_PROCNUM_OUT_OF_RANGE returned, trying old method\n");
  161. Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
  162. Values,
  163. num_vals,
  164. NewValueBuf,
  165. pTotalSize);
  166. }
  167. }
  168. RpcEndExcept
  169. } else {
  170. DWORD dwVersion;
  171. //
  172. // try new method first
  173. //
  174. RpcTryExcept {
  175. Error = (LONG)BaseRegQueryMultipleValues2(DereferenceRemoteHandle( hKey ),
  176. Values,
  177. num_vals,
  178. NewValueBuf,
  179. pTotalSize,
  180. &RequiredSize);
  181. *pTotalSize = RequiredSize;
  182. }
  183. RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  184. Error = RpcExceptionCode();
  185. if( Error == RPC_S_PROCNUM_OUT_OF_RANGE) {
  186. //
  187. // old server
  188. //
  189. //DbgPrint("WINREG: RPC_S_PROCNUM_OUT_OF_RANGE returned, trying old method\n");
  190. Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
  191. Values,
  192. num_vals,
  193. NewValueBuf,
  194. pTotalSize);
  195. }
  196. }
  197. RpcEndExcept
  198. if ((Error == ERROR_SUCCESS) &&
  199. (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion))) {
  200. //
  201. // Win95's RegQueryMultipleValues doesn't return Unicode
  202. // value data, so do not try and convert it back to Ansi.
  203. //
  204. for (i=0; i<num_vals; i++) {
  205. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  206. val_list[i].ve_type = Values[i].rv_type;
  207. val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + Values[i].rv_valueptr);
  208. }
  209. CopyMemory(lpValueBuf,NewValueBuf,TotalSize);
  210. if (ldwTotsize != NULL) {
  211. *ldwTotsize = TotalSize;
  212. }
  213. goto Cleanup;
  214. }
  215. }
  216. if (Error == ERROR_SUCCESS) {
  217. //
  218. // Convert results back.
  219. //
  220. DataOffset = 0;
  221. for (i=0; i < num_vals; i++) {
  222. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  223. val_list[i].ve_type = Values[i].rv_type;
  224. val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + DataOffset);
  225. if ((val_list[i].ve_type == REG_SZ) ||
  226. (val_list[i].ve_type == REG_EXPAND_SZ) ||
  227. (val_list[i].ve_type == REG_MULTI_SZ)) {
  228. Status = RtlUnicodeToMultiByteN(lpValueBuf + DataOffset,
  229. Values[i].rv_valuelen/sizeof(WCHAR),
  230. &AnsiLength,
  231. (PWCH)(NewValueBuf + Values[i].rv_valueptr),
  232. Values[i].rv_valuelen);
  233. if (!NT_SUCCESS(Status)) {
  234. Error = RtlNtStatusToDosError( Status );
  235. }
  236. val_list[i].ve_valuelen = AnsiLength;
  237. DataOffset += AnsiLength;
  238. } else {
  239. CopyMemory(lpValueBuf + DataOffset,
  240. NewValueBuf + Values[i].rv_valueptr,
  241. Values[i].rv_valuelen);
  242. DataOffset += Values[i].rv_valuelen;
  243. }
  244. //
  245. // Round DataOffset up to dword boundary.
  246. //
  247. DataOffset = (DataOffset + sizeof(DWORD) - 1) & ~(sizeof(DWORD)-1);
  248. }
  249. if (ldwTotsize != NULL) {
  250. *ldwTotsize = DataOffset;
  251. }
  252. } else if (Error == ERROR_MORE_DATA) {
  253. //
  254. // We need to thunk the Unicode required bytes back to Ansi. But
  255. // there is not really any way to do this without having the data
  256. // available. So just return the required bytes for the Unicode
  257. // data, as this will always be enough.
  258. //
  259. if (ldwTotsize != NULL) {
  260. *ldwTotsize = *pTotalSize;
  261. }
  262. }
  263. Cleanup:
  264. if (NewValueBuf != NULL) {
  265. RtlFreeHeap(RtlProcessHeap(),0,NewValueBuf);
  266. }
  267. for (i=0; i<num_vals; i++) {
  268. if (Names[i].Buffer != NULL) {
  269. RtlFreeUnicodeString(&Names[i]);
  270. }
  271. }
  272. RtlFreeHeap(RtlProcessHeap(),0,Values);
  273. RtlFreeHeap(RtlProcessHeap(),0,Names);
  274. ExitCleanup:
  275. CLOSE_LOCAL_HANDLE(TempHandle);
  276. return Error;
  277. }
  278. WINADVAPI
  279. LONG
  280. APIENTRY
  281. RegQueryMultipleValuesW (
  282. HKEY hKey,
  283. PVALENTW val_list,
  284. DWORD num_vals,
  285. LPWSTR lpValueBuf,
  286. LPDWORD ldwTotsize
  287. )
  288. /*++
  289. Routine Description:
  290. The RegQueryMultipleValues function retrieves a list of
  291. data type/data pairs for a list of value names associated
  292. with an open registry key.
  293. Parameters:
  294. hKey
  295. Identifies a currently open key or any of the pre-defined reserved handle values:
  296. HKEY_CLASSES_ROOT
  297. HEY_CURRENT_USER
  298. HKEY_LOCAL_MACHINE
  299. HKEY_USERS
  300. valList
  301. Points to an array of structures describing one or more value entries. This
  302. contains the value names of the values to be queried. Refer to Appendix A for a
  303. description of VALUE_ENTRY structure.
  304. num_vals
  305. Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
  306. fractional extra space pointed to by valList is ignored.
  307. lpValueBuf
  308. The output buffer for returning value information (value names and value data). Data
  309. is DWORD aligned with pads inserted as necessary.
  310. ldwTotsize
  311. The total size of the output buffer pointed to by lpValueBuf. On output ldwTotsize
  312. contains the number of bytes used including pads. If lpValueBuf was too short, then on
  313. output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
  314. filled up to the size specified by ldwTotsize on input.
  315. Return value:
  316. If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
  317. of the error value which can be returned by RegQueryValueEx. In addition, if
  318. either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
  319. If the function is unable to instantiate/access the provider of the
  320. dynamic key, it will return ERROR_CANTREAD. If the total length of the
  321. requested data (valListLength + ldwTotSize) is more than the system limit of one
  322. megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
  323. megabyte of data is returned.
  324. --*/
  325. {
  326. NTSTATUS Status;
  327. PRVALENT Values;
  328. PUNICODE_STRING Names;
  329. LONG Error;
  330. ULONG i;
  331. ULONG DataLength;
  332. ULONG InputLength;
  333. LPDWORD pTotalSize;
  334. DWORD TotalSize;
  335. DWORD StringLength;
  336. HKEY TempHandle = NULL;
  337. DWORD RequiredSize;
  338. hKey = MapPredefinedHandle(hKey, &TempHandle);
  339. if (hKey == NULL) {
  340. Error = ERROR_INVALID_HANDLE;
  341. goto ExitCleanup;
  342. }
  343. //
  344. // Allocate an array of RVALENTs to describe the input value names
  345. //
  346. Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
  347. if (Values == NULL) {
  348. Error = ERROR_OUTOFMEMORY;
  349. goto ExitCleanup;
  350. }
  351. ZeroMemory(Values, sizeof(RVALENT)*num_vals);
  352. //
  353. // Allocate an array of UNICODE_STRINGs to contain the input names
  354. //
  355. Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
  356. if (Names == NULL) {
  357. RtlFreeHeap(RtlProcessHeap(), 0, Values);
  358. Error = ERROR_OUTOFMEMORY;
  359. goto ExitCleanup;
  360. }
  361. ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
  362. //
  363. // Copy and convert the value names to UNICODE_STRINGs
  364. // Note that we have to copy the value names because RPC tromps
  365. // on them.
  366. //
  367. for (i=0; i<num_vals; i++) {
  368. StringLength = wcslen(val_list[i].ve_valuename)*sizeof(WCHAR);
  369. Names[i].Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, StringLength + sizeof(UNICODE_NULL));
  370. if (Names[i].Buffer == NULL) {
  371. goto error_exit;
  372. }
  373. Names[i].Length = Names[i].MaximumLength = (USHORT)StringLength + sizeof(UNICODE_NULL);
  374. CopyMemory(Names[i].Buffer, val_list[i].ve_valuename, StringLength + sizeof(UNICODE_NULL));
  375. Values[i].rv_valuename = &Names[i];
  376. }
  377. if (ldwTotsize == NULL) {
  378. TotalSize = 0;
  379. pTotalSize = &TotalSize;
  380. } else {
  381. pTotalSize = ldwTotsize;
  382. }
  383. //
  384. // Call the Base API, passing it the supplied parameters and the
  385. // counted Unicode strings.
  386. //
  387. if (IsLocalHandle(hKey)) {
  388. //
  389. // try new method first
  390. //
  391. RpcTryExcept {
  392. Error = (LONG)LocalBaseRegQueryMultipleValues2(hKey,
  393. Values,
  394. num_vals,
  395. (LPSTR)lpValueBuf,
  396. pTotalSize,
  397. &RequiredSize);
  398. *pTotalSize = RequiredSize;
  399. }
  400. RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  401. Error = RpcExceptionCode();
  402. if( Error == RPC_S_PROCNUM_OUT_OF_RANGE) {
  403. //
  404. // old server
  405. //
  406. //DbgPrint("WINREG: RPC_S_PROCNUM_OUT_OF_RANGE returned, trying old method\n");
  407. Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
  408. Values,
  409. num_vals,
  410. (LPSTR)lpValueBuf,
  411. pTotalSize);
  412. }
  413. }
  414. RpcEndExcept
  415. } else {
  416. DWORD dwVersion;
  417. if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
  418. //
  419. // We cannot support RegQueryMultipleValuesW to Win95 servers
  420. // since they do not return Unicode value data.
  421. //
  422. Error = ERROR_CALL_NOT_IMPLEMENTED;
  423. } else {
  424. //
  425. // try new method first
  426. //
  427. RpcTryExcept {
  428. //DbgPrint("WINREG: RPC_S_PROCNUM_OUT_OF_RANGE returned, trying old method\n");
  429. Error = (LONG)BaseRegQueryMultipleValues2(DereferenceRemoteHandle( hKey ),
  430. Values,
  431. num_vals,
  432. (LPSTR)lpValueBuf,
  433. pTotalSize,
  434. &RequiredSize);
  435. *pTotalSize = RequiredSize;
  436. }
  437. RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  438. Error = RpcExceptionCode();
  439. if( Error == RPC_S_PROCNUM_OUT_OF_RANGE) {
  440. //
  441. // old server
  442. //
  443. Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
  444. Values,
  445. num_vals,
  446. (LPSTR)lpValueBuf,
  447. pTotalSize);
  448. }
  449. }
  450. RpcEndExcept
  451. }
  452. }
  453. if (Error == ERROR_SUCCESS) {
  454. //
  455. // Convert results back.
  456. //
  457. for (i=0; i < num_vals; i++) {
  458. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  459. val_list[i].ve_valueptr = (DWORD_PTR)((LPCSTR)lpValueBuf + Values[i].rv_valueptr);
  460. val_list[i].ve_type = Values[i].rv_type;
  461. }
  462. }
  463. error_exit:
  464. for (i=0; i < num_vals; i++) {
  465. if (Names[i].Buffer != NULL) {
  466. RtlFreeHeap(RtlProcessHeap(), 0, Names[i].Buffer);
  467. }
  468. }
  469. RtlFreeHeap(RtlProcessHeap(),0,Values);
  470. RtlFreeHeap(RtlProcessHeap(),0,Names);
  471. ExitCleanup:
  472. CLOSE_LOCAL_HANDLE(TempHandle);
  473. return Error;
  474. }