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.

607 lines
19 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Regeval.c
  5. Abstract:
  6. This module contains the client side wrappers for the Win32 Registry
  7. enumerate value APIs. That is:
  8. - RegEnumValueExA
  9. - RegEnumValueExW
  10. Author:
  11. David J. Gilman (davegi) 18-Mar-1992
  12. Notes:
  13. See the notes in server\regeval.c.
  14. --*/
  15. #include <rpc.h>
  16. #include "regrpc.h"
  17. #include "client.h"
  18. LONG
  19. RegEnumValueA (
  20. HKEY hKey,
  21. DWORD dwIndex,
  22. LPSTR lpValueName,
  23. LPDWORD lpcbValueName,
  24. LPDWORD lpReserved,
  25. LPDWORD lpType,
  26. LPBYTE lpData,
  27. LPDWORD lpcbData
  28. )
  29. /*++
  30. Routine Description:
  31. Win32 ANSI RPC wrapper for enumerating values.
  32. --*/
  33. {
  34. UNICODE_STRING Name;
  35. ANSI_STRING AnsiString;
  36. NTSTATUS Status;
  37. LONG Error = ERROR_SUCCESS;
  38. DWORD ValueType;
  39. DWORD ValueLength;
  40. DWORD InputLength;
  41. PWSTR UnicodeValueBuffer;
  42. ULONG UnicodeValueLength;
  43. PSTR AnsiValueBuffer;
  44. ULONG AnsiValueLength;
  45. ULONG Index;
  46. BOOLEAN Win95Server = FALSE;
  47. ULONG cbAnsi = 0;
  48. HKEY TempHandle = NULL;
  49. #if DBG
  50. if ( BreakPointOnEntry ) {
  51. DbgBreakPoint();
  52. }
  53. #endif
  54. //
  55. // Validate dependency between lpData and lpcbData parameters.
  56. //
  57. if( ARGUMENT_PRESENT( lpReserved ) ||
  58. (ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData ))) ||
  59. (!ARGUMENT_PRESENT(lpcbValueName)) || (!ARGUMENT_PRESENT(lpValueName)) ) {
  60. return ERROR_INVALID_PARAMETER;
  61. }
  62. hKey = MapPredefinedHandle( hKey, &TempHandle );
  63. if( hKey == NULL ) {
  64. Error = ERROR_INVALID_HANDLE;
  65. goto ExitCleanup;
  66. }
  67. //
  68. // Allocate temporary buffer for the Name
  69. //
  70. Name.Length = 0;
  71. Name.MaximumLength = (USHORT)((*lpcbValueName + 1) * sizeof( WCHAR ));
  72. Name.Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, Name.MaximumLength );
  73. if( Name.Buffer == NULL ) {
  74. Error = ERROR_NOT_ENOUGH_MEMORY;
  75. goto ExitCleanup;
  76. }
  77. //
  78. // Call the Base API passing it a pointer to the counted Unicode
  79. // strings for the value name. Note that zero bytes are transmitted (i.e.
  80. // InputLength = 0) for the data.
  81. //
  82. if (ARGUMENT_PRESENT( lpcbData )) {
  83. ValueLength = *lpcbData;
  84. }
  85. else {
  86. ValueLength = 0;
  87. }
  88. InputLength = 0;
  89. if( IsLocalHandle( hKey )) {
  90. Error = (LONG)LocalBaseRegEnumValue (
  91. hKey,
  92. dwIndex,
  93. &Name,
  94. &ValueType,
  95. lpData,
  96. &ValueLength,
  97. &InputLength
  98. );
  99. ASSERT( Name.Buffer );
  100. } else {
  101. DWORD dwVersion;
  102. //
  103. // Check for a downlevel Win95 server, which requires
  104. // us to work around their BaseRegEnumValue bugs.
  105. // The returned ValueLength is one WCHAR too large AND
  106. // they trash two bytes beyond the end of the buffer
  107. // for REG_SZ, REG_MULTI_SZ, and REG_EXPAND_SZ
  108. //
  109. Win95Server = IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion);
  110. if (Win95Server) {
  111. LPBYTE lpWin95Data;
  112. //
  113. // This is a Win95 server.
  114. // Allocate a new buffer that is two bytes larger than
  115. // the old one so they can trash the last two bytes.
  116. //
  117. lpWin95Data = RtlAllocateHeap(RtlProcessHeap(),
  118. 0,
  119. ValueLength+sizeof(WCHAR));
  120. if (lpWin95Data == NULL) {
  121. Error = ERROR_NOT_ENOUGH_MEMORY;
  122. } else {
  123. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  124. dwIndex,
  125. &Name,
  126. &ValueType,
  127. lpWin95Data,
  128. &ValueLength,
  129. &InputLength);
  130. if (Error == ERROR_SUCCESS) {
  131. if ((ValueType == REG_SZ) ||
  132. (ValueType == REG_MULTI_SZ) ||
  133. (ValueType == REG_EXPAND_SZ)) {
  134. //
  135. // The returned length is one WCHAR too large
  136. // and the last two bytes of the buffer are trashed.
  137. //
  138. ValueLength -= sizeof(WCHAR);
  139. }
  140. CopyMemory(lpData, lpWin95Data, ValueLength);
  141. }
  142. RtlFreeHeap(RtlProcessHeap(),0,lpWin95Data);
  143. }
  144. } else {
  145. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  146. dwIndex,
  147. &Name,
  148. &ValueType,
  149. lpData,
  150. &ValueLength,
  151. &InputLength);
  152. }
  153. }
  154. //
  155. // If no error or callers buffer too small, and type is one of the null
  156. // terminated string types, then do the UNICODE to ANSI translation.
  157. // We handle the buffer too small case, because the callers buffer may
  158. // be big enough for the ANSI representation, but not the UNICODE one.
  159. // In this case, we need to allocate a buffer big enough, do the query
  160. // again and then the translation into the callers buffer.
  161. //
  162. if ((Error == ERROR_SUCCESS || Error == ERROR_MORE_DATA) &&
  163. ARGUMENT_PRESENT( lpcbData ) &&
  164. (ValueType == REG_SZ ||
  165. ValueType == REG_EXPAND_SZ ||
  166. ValueType == REG_MULTI_SZ)
  167. ) {
  168. UnicodeValueLength = ValueLength;
  169. AnsiValueBuffer = lpData;
  170. AnsiValueLength = ARGUMENT_PRESENT( lpcbData )? *lpcbData : 0;
  171. //
  172. // Allocate a buffer for the UNICODE value and reissue the query.
  173. //
  174. UnicodeValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0,
  175. UnicodeValueLength
  176. );
  177. if (UnicodeValueBuffer == NULL) {
  178. Error = ERROR_NOT_ENOUGH_MEMORY;
  179. } else {
  180. InputLength = 0;
  181. if( IsLocalHandle( hKey )) {
  182. Error = (LONG)LocalBaseRegEnumValue (
  183. hKey,
  184. dwIndex,
  185. &Name,
  186. &ValueType,
  187. (LPBYTE)UnicodeValueBuffer,
  188. &ValueLength,
  189. &InputLength
  190. );
  191. //
  192. // Make sure that the local side didn't destroy the
  193. // Buffer in the Name
  194. //
  195. ASSERT(Name.Buffer);
  196. } else {
  197. if (Win95Server) {
  198. LPBYTE lpWin95Data;
  199. //
  200. // This is a Win95 server.
  201. // Allocate a new buffer that is two bytes larger than
  202. // the old one so they can trash the last two bytes.
  203. //
  204. lpWin95Data = RtlAllocateHeap(RtlProcessHeap(),
  205. 0,
  206. ValueLength+sizeof(WCHAR));
  207. if (lpWin95Data == NULL) {
  208. Error = ERROR_NOT_ENOUGH_MEMORY;
  209. } else {
  210. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  211. dwIndex,
  212. &Name,
  213. &ValueType,
  214. lpWin95Data,
  215. &ValueLength,
  216. &InputLength);
  217. if (Error == ERROR_SUCCESS) {
  218. if ((ValueType == REG_SZ) ||
  219. (ValueType == REG_MULTI_SZ) ||
  220. (ValueType == REG_EXPAND_SZ)) {
  221. //
  222. // The returned length is one WCHAR too large
  223. // and the last two bytes of the buffer are trashed.
  224. //
  225. ValueLength -= sizeof(WCHAR);
  226. }
  227. CopyMemory(UnicodeValueBuffer, lpWin95Data, ValueLength);
  228. }
  229. RtlFreeHeap(RtlProcessHeap(),0,lpWin95Data);
  230. }
  231. } else {
  232. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  233. dwIndex,
  234. &Name,
  235. &ValueType,
  236. (LPBYTE)UnicodeValueBuffer,
  237. &ValueLength,
  238. &InputLength);
  239. }
  240. }
  241. // Compute needed buffer size , cbAnsi will keeps the byte
  242. // counts to keep MBCS string after following step.
  243. RtlUnicodeToMultiByteSize( &cbAnsi ,
  244. UnicodeValueBuffer ,
  245. ValueLength );
  246. // If we could not store all MBCS string to buffer that
  247. // Apps gives me. We set ERROR_MORE_DATA to Error
  248. if( ARGUMENT_PRESENT( lpcbData ) ) {
  249. if( cbAnsi > *lpcbData && lpData != NULL ) {
  250. Error = ERROR_MORE_DATA;
  251. }
  252. }
  253. }
  254. if ((Error == ERROR_SUCCESS) && (AnsiValueBuffer != NULL)) {
  255. //
  256. // We have a UNICODE value, so translate it to ANSI in the callers
  257. // buffer. In the case where the caller's buffer was big enough
  258. // for the UNICODE version, we do the conversion in place, which
  259. // works since the ANSI version is smaller than the UNICODE version.
  260. //
  261. Index = 0;
  262. Status = RtlUnicodeToMultiByteN( AnsiValueBuffer,
  263. AnsiValueLength,
  264. &Index,
  265. UnicodeValueBuffer,
  266. UnicodeValueLength
  267. );
  268. if (!NT_SUCCESS( Status )) {
  269. Error = RtlNtStatusToDosError( Status );
  270. }
  271. cbAnsi = Index;
  272. }
  273. //
  274. // Free the unicode buffer if it was successfully allocated
  275. //
  276. if (UnicodeValueBuffer != NULL) {
  277. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValueBuffer );
  278. }
  279. //
  280. // Return the length of the ANSI version to the caller.
  281. //
  282. ValueLength = cbAnsi;
  283. //
  284. // Special hack to help out all the peopl who
  285. // believe the length of a NULL terminated string is
  286. // strlen(foo) instead of strlen(foo) + 1.
  287. // If the last character of the buffer is not a NULL
  288. // and there is enough space left in the caller's buffer,
  289. // slap a NULL in there to prevent him from going nuts
  290. // trying to do a strlen().
  291. //
  292. if (ARGUMENT_PRESENT( lpData ) &&
  293. (*lpcbData > ValueLength) &&
  294. (ValueLength > 0) &&
  295. (lpData[ValueLength-1] != '\0')) {
  296. lpData[ValueLength] = '\0';
  297. }
  298. }
  299. //
  300. // Return the value type and data length if requested and we have it.
  301. //
  302. if (Error == ERROR_SUCCESS || Error == ERROR_MORE_DATA) {
  303. if (lpcbData != NULL) {
  304. *lpcbData = ValueLength;
  305. }
  306. if (lpType != NULL) {
  307. *lpType = ValueType;
  308. }
  309. }
  310. //
  311. // If the information was not succesfully queried return the error.
  312. //
  313. if( Error != ERROR_SUCCESS ) {
  314. // free allocated buffer
  315. RtlFreeHeap( RtlProcessHeap(), 0, Name.Buffer );
  316. goto ExitCleanup;
  317. }
  318. //
  319. // Subtract the NULL from the Length. This was added by the server
  320. // so that RPC would transmit it.
  321. //
  322. if ( Name.Length > 0 ) {
  323. Name.Length -= sizeof( UNICODE_NULL );
  324. }
  325. //
  326. // Convert the name to ANSI.
  327. //
  328. AnsiString.MaximumLength = ( USHORT ) *lpcbValueName;
  329. AnsiString.Buffer = lpValueName;
  330. Status = RtlUnicodeStringToAnsiString(
  331. &AnsiString,
  332. &Name,
  333. FALSE
  334. );
  335. // free allocated buffer
  336. RtlFreeHeap( RtlProcessHeap(), 0, Name.Buffer );
  337. //
  338. // If the name conversion failed, map and return the error.
  339. //
  340. if( ! NT_SUCCESS( Status )) {
  341. Error = RtlNtStatusToDosError( Status );
  342. goto ExitCleanup;
  343. }
  344. //
  345. // Update the name length return parameter.
  346. //
  347. *lpcbValueName = AnsiString.Length;
  348. ExitCleanup:
  349. CLOSE_LOCAL_HANDLE(TempHandle);
  350. return Error;
  351. }
  352. LONG
  353. RegEnumValueW (
  354. HKEY hKey,
  355. DWORD dwIndex,
  356. LPWSTR lpValueName,
  357. LPDWORD lpcbValueName,
  358. LPDWORD lpReserved,
  359. LPDWORD lpType,
  360. LPBYTE lpData,
  361. LPDWORD lpcbData
  362. )
  363. /*++
  364. Routine Description:
  365. Win32 Unicode RPC wrapper for enumerating values.
  366. --*/
  367. {
  368. UNICODE_STRING Name;
  369. LONG Error;
  370. DWORD InputLength;
  371. DWORD ValueLength;
  372. DWORD ValueType;
  373. HKEY TempHandle = NULL;
  374. #if DBG
  375. if ( BreakPointOnEntry ) {
  376. DbgBreakPoint();
  377. }
  378. #endif
  379. //
  380. // Validate dependency between lpData and lpcbData parameters.
  381. //
  382. if( ARGUMENT_PRESENT( lpReserved ) ||
  383. (ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData ))) ||
  384. (!ARGUMENT_PRESENT(lpcbValueName)) || (!ARGUMENT_PRESENT(lpValueName)) ) {
  385. return ERROR_INVALID_PARAMETER;
  386. }
  387. hKey = MapPredefinedHandle( hKey, &TempHandle );
  388. if( hKey == NULL ) {
  389. Error = ERROR_INVALID_HANDLE;
  390. goto ExitCleanup;
  391. }
  392. Name.Length = 0;
  393. Name.MaximumLength = ( USHORT )( *lpcbValueName << 1 );
  394. Name.Buffer = lpValueName;
  395. //
  396. // Call the Base API passing it a pointer to the counted Unicode
  397. // string for the name and return the results. Note that zero bytes
  398. // are transmitted (i.e.InputLength = 0) for the data.
  399. //
  400. InputLength = 0;
  401. ValueLength = ( ARGUMENT_PRESENT( lpcbData ) )? *lpcbData : 0;
  402. if( IsLocalHandle( hKey )) {
  403. Error = (LONG)LocalBaseRegEnumValue (
  404. hKey,
  405. dwIndex,
  406. &Name,
  407. &ValueType,
  408. lpData,
  409. &ValueLength,
  410. &InputLength
  411. );
  412. } else {
  413. DWORD dwVersion;
  414. if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
  415. LPBYTE lpWin95Data;
  416. //
  417. // This is a Win95 server.
  418. // Allocate a new buffer that is two bytes larger than
  419. // the old one so they can trash the last two bytes.
  420. //
  421. lpWin95Data = RtlAllocateHeap(RtlProcessHeap(),
  422. 0,
  423. ValueLength+sizeof(WCHAR));
  424. if (lpWin95Data == NULL) {
  425. Error = ERROR_NOT_ENOUGH_MEMORY;
  426. goto ExitCleanup;
  427. } else {
  428. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  429. dwIndex,
  430. &Name,
  431. &ValueType,
  432. lpWin95Data,
  433. &ValueLength,
  434. &InputLength);
  435. if (Error == ERROR_SUCCESS) {
  436. if ((ValueType == REG_SZ) ||
  437. (ValueType == REG_MULTI_SZ) ||
  438. (ValueType == REG_EXPAND_SZ)) {
  439. //
  440. // The returned length is one WCHAR too large
  441. // and the last two bytes of the buffer are trashed.
  442. //
  443. ValueLength -= sizeof(WCHAR);
  444. }
  445. CopyMemory(lpData, lpWin95Data, ValueLength);
  446. }
  447. RtlFreeHeap(RtlProcessHeap(),0,lpWin95Data);
  448. }
  449. } else {
  450. Error = (LONG)BaseRegEnumValue (DereferenceRemoteHandle( hKey ),
  451. dwIndex,
  452. &Name,
  453. &ValueType,
  454. lpData,
  455. &ValueLength,
  456. &InputLength);
  457. }
  458. }
  459. //
  460. // Special hack to help out all the people who
  461. // believe the length of a NULL terminated string is
  462. // strlen(foo) instead of strlen(foo) + 1.
  463. // If the last character of the buffer is not a NULL
  464. // and there is enough space left in the caller's buffer,
  465. // slap a NULL in there to prevent him from going nuts
  466. // trying to do a strlen().
  467. //
  468. if ( (Error == ERROR_SUCCESS) &&
  469. ARGUMENT_PRESENT( lpData ) &&
  470. ( (ValueType == REG_SZ) ||
  471. (ValueType == REG_EXPAND_SZ) ||
  472. (ValueType == REG_MULTI_SZ)) &&
  473. ( ValueLength > sizeof(WCHAR))) {
  474. UNALIGNED WCHAR *String = (UNALIGNED WCHAR *)lpData;
  475. DWORD Length = ValueLength/sizeof(WCHAR);
  476. if ((String[Length-1] != UNICODE_NULL) &&
  477. (ValueLength+sizeof(WCHAR) <= *lpcbData)) {
  478. String[Length] = UNICODE_NULL;
  479. }
  480. }
  481. //
  482. // Don't count the NUL.
  483. //
  484. if( Name.Length != 0 ) {
  485. *lpcbValueName = ( Name.Length >> 1 ) - 1;
  486. }
  487. if( ARGUMENT_PRESENT( lpcbData ) ) {
  488. *lpcbData = ValueLength;
  489. }
  490. if ( ARGUMENT_PRESENT( lpType )) {
  491. *lpType = ValueType;
  492. }
  493. ExitCleanup:
  494. CLOSE_LOCAL_HANDLE(TempHandle);
  495. return Error;
  496. }