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.

1990 lines
45 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dmreg.c
  5. Abstract:
  6. Contains the registry access routines for the Config Database Manager
  7. Author:
  8. John Vert (jvert) 24-Apr-1996
  9. Revision History:
  10. --*/
  11. #include "dmp.h"
  12. #include <align.h>
  13. #if NO_SHARED_LOCKS
  14. extern CRITICAL_SECTION gLockDmpRoot;
  15. #else
  16. extern RTL_RESOURCE gLockDmpRoot;
  17. #endif
  18. HDMKEY
  19. DmGetRootKey(
  20. IN DWORD samDesired
  21. )
  22. /*++
  23. Routine Description:
  24. Opens the registry key at the root of the cluster registry database
  25. Arguments:
  26. samDesired - Supplies requested security access
  27. Return Value:
  28. A handle to the opened registry key.
  29. NULL on error. LastError will be set to the specific error code.
  30. --*/
  31. {
  32. DWORD Error;
  33. PDMKEY Key;
  34. Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+sizeof(WCHAR));
  35. if (Key == NULL) {
  36. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  37. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  38. return(NULL);
  39. }
  40. //
  41. // Acquire DM root lock to synchronize with DmRollbackRegistry.
  42. //
  43. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  44. Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  45. DmpClusterParametersKeyName,
  46. 0,
  47. samDesired,
  48. &Key->hKey);
  49. if (Error != ERROR_SUCCESS) {
  50. LocalFree(Key);
  51. SetLastError(Error);
  52. Key = NULL;
  53. goto FnExit;
  54. }
  55. Key->Name[0] = '\0';
  56. Key->GrantedAccess = samDesired;
  57. EnterCriticalSection(&KeyLock);
  58. InsertHeadList(&KeyList, &Key->ListEntry);
  59. InitializeListHead(&Key->NotifyList);
  60. LeaveCriticalSection(&KeyLock);
  61. FnExit:
  62. RELEASE_LOCK(gLockDmpRoot);
  63. return((HDMKEY)Key);
  64. }
  65. DWORD
  66. DmCloseKey(
  67. IN HDMKEY hKey
  68. )
  69. /*++
  70. Routine Description:
  71. Closes a handle to an open HDMKEY key.
  72. Arguments:
  73. hKey - Supplies the handle to be closed.
  74. Return Value:
  75. ERROR_SUCCESS if successful
  76. Win32 error code otherwise.
  77. --*/
  78. {
  79. DWORD Error = ERROR_SUCCESS;
  80. PDMKEY Key;
  81. //
  82. // Nobody better EVER close one of the global keys.
  83. //
  84. CL_ASSERT(hKey != DmClusterParametersKey);
  85. CL_ASSERT(hKey != DmResourcesKey);
  86. CL_ASSERT(hKey != DmResourceTypesKey);
  87. CL_ASSERT(hKey != DmQuorumKey);
  88. CL_ASSERT(hKey != DmGroupsKey);
  89. CL_ASSERT(hKey != DmNodesKey);
  90. CL_ASSERT(hKey != DmNetworksKey);
  91. CL_ASSERT(hKey != DmNetInterfacesKey);
  92. Key = (PDMKEY)hKey;
  93. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  94. //if the key was deleted and invalidated and couldnt be reopened
  95. // it will be set to NULL, in this case we dont call regclosekey
  96. if( Key == NULL ) goto FnExit;
  97. if (ISKEYDELETED(Key))
  98. goto CleanupKey;
  99. Error = RegCloseKey(Key->hKey);
  100. if (Error != ERROR_SUCCESS)
  101. {
  102. CL_LOGFAILURE(Error);
  103. goto FnExit;
  104. }
  105. CleanupKey:
  106. EnterCriticalSection(&KeyLock);
  107. RemoveEntryList(&Key->ListEntry);
  108. DmpRundownNotify(Key);
  109. LeaveCriticalSection(&KeyLock);
  110. LocalFree(Key);
  111. FnExit:
  112. RELEASE_LOCK(gLockDmpRoot);
  113. return(Error);
  114. }
  115. HDMKEY
  116. DmCreateKey(
  117. IN HDMKEY hKey,
  118. IN LPCWSTR lpSubKey,
  119. IN DWORD dwOptions,
  120. IN DWORD samDesired,
  121. IN OPTIONAL LPVOID lpSecurityDescriptor,
  122. OUT LPDWORD lpDisposition
  123. )
  124. /*++
  125. Routine Description:
  126. Creates a key in the cluster registry. If the key exists, it
  127. is opened. If it does not exist, it is created on all nodes in
  128. the cluster.
  129. Arguments:
  130. hKey - Supplies the key that the create is relative to.
  131. lpSubKey - Supplies the key name relative to hKey
  132. dwOptions - Supplies any registry option flags.
  133. samDesired - Supplies desired security access mask
  134. lpSecurityDescriptor - Supplies security for the newly created key.
  135. Disposition - Returns whether the key was opened (REG_OPENED_EXISTING_KEY)
  136. or created (REG_CREATED_NEW_KEY)
  137. Return Value:
  138. A handle to the specified key if successful
  139. NULL otherwise. LastError will be set to the specific error code.
  140. --*/
  141. {
  142. PDMKEY Parent;
  143. PDMKEY Key=NULL;
  144. DWORD NameLength;
  145. DWORD Status = ERROR_SUCCESS;
  146. HDMKEY NewKey;
  147. PDM_CREATE_KEY_UPDATE CreateUpdate = NULL;
  148. DWORD SecurityLength;
  149. // if this is a request to create a volatile key, refuse it
  150. // we dont support volatile keys in the cluster hive since
  151. // we cant roll back the cluster hive then.
  152. if (dwOptions == REG_OPTION_VOLATILE)
  153. {
  154. Status = ERROR_INVALID_PARAMETER;
  155. goto FnExit;
  156. }
  157. //
  158. // Issue a global update to create the key.
  159. //
  160. Parent = (PDMKEY)hKey;
  161. //
  162. // Allocate the DMKEY structure.
  163. //
  164. NameLength = (lstrlenW(Parent->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
  165. Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+NameLength);
  166. if (Key == NULL) {
  167. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  168. Status = ERROR_NOT_ENOUGH_MEMORY;
  169. goto FnExit;
  170. }
  171. //
  172. // Create the key name
  173. //
  174. lstrcpyW(Key->Name, Parent->Name);
  175. if (Key->Name[0] != UNICODE_NULL) {
  176. lstrcatW(Key->Name, L"\\");
  177. }
  178. lstrcatW(Key->Name, lpSubKey);
  179. Key->GrantedAccess = samDesired;
  180. //get the length of the security structure
  181. if (ARGUMENT_PRESENT(lpSecurityDescriptor)) {
  182. SecurityLength = GetSecurityDescriptorLength(lpSecurityDescriptor);
  183. } else {
  184. SecurityLength = 0;
  185. }
  186. CreateUpdate = (PDM_CREATE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, sizeof(DM_CREATE_KEY_UPDATE));
  187. if (CreateUpdate == NULL) {
  188. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  189. Status = ERROR_NOT_ENOUGH_MEMORY;
  190. goto FnExit;
  191. }
  192. //
  193. // Issue the update.
  194. //
  195. CreateUpdate->lpDisposition = lpDisposition;
  196. CreateUpdate->phKey = &Key->hKey;
  197. CreateUpdate->samDesired = samDesired;
  198. CreateUpdate->dwOptions = dwOptions;
  199. if (ARGUMENT_PRESENT(lpSecurityDescriptor)) {
  200. CreateUpdate->SecurityPresent = TRUE;
  201. } else {
  202. CreateUpdate->SecurityPresent = FALSE;
  203. }
  204. Status = GumSendUpdateEx(GumUpdateRegistry,
  205. DmUpdateCreateKey,
  206. 3,
  207. sizeof(DM_CREATE_KEY_UPDATE),
  208. CreateUpdate,
  209. (lstrlenW(Key->Name)+1)*sizeof(WCHAR),
  210. Key->Name,
  211. SecurityLength,
  212. lpSecurityDescriptor);
  213. if (Status != ERROR_SUCCESS)
  214. {
  215. goto FnExit;
  216. }
  217. EnterCriticalSection(&KeyLock);
  218. InsertHeadList(&KeyList, &Key->ListEntry);
  219. InitializeListHead(&Key->NotifyList);
  220. LeaveCriticalSection(&KeyLock);
  221. FnExit:
  222. if (CreateUpdate) LocalFree(CreateUpdate);
  223. if (Status != ERROR_SUCCESS)
  224. {
  225. if (Key) LocalFree(Key);
  226. SetLastError(Status);
  227. return(NULL);
  228. }
  229. else
  230. {
  231. return ((HDMKEY)Key);
  232. }
  233. }
  234. HDMKEY
  235. DmOpenKey(
  236. IN HDMKEY hKey,
  237. IN LPCWSTR lpSubKey,
  238. IN DWORD samDesired
  239. )
  240. /*++
  241. Routine Description:
  242. Opens a key in the cluster registry. If the key exists, it
  243. is opened. If it does not exist, the call fails.
  244. Arguments:
  245. hKey - Supplies the key that the open is relative to.
  246. lpSubKey - Supplies the key name relative to hKey
  247. samDesired - Supplies desired security access mask
  248. Return Value:
  249. A handle to the specified key if successful
  250. NULL otherwise. LastError will be set to the specific error code.
  251. --*/
  252. {
  253. PDMKEY Parent;
  254. PDMKEY Key=NULL;
  255. DWORD NameLength;
  256. DWORD Status = ERROR_SUCCESS;
  257. Parent = (PDMKEY)hKey;
  258. //hold the shared lock
  259. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  260. //check if the key was deleted and invalidated
  261. if (ISKEYDELETED(Parent))
  262. {
  263. Status = ERROR_KEY_DELETED;
  264. goto FnExit;
  265. }
  266. //
  267. // Allocate the DMKEY structure.
  268. //
  269. NameLength = (lstrlenW(Parent->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
  270. Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+NameLength);
  271. if (Key == NULL) {
  272. Status = ERROR_NOT_ENOUGH_MEMORY;
  273. CL_UNEXPECTED_ERROR(Status);
  274. goto FnExit;
  275. }
  276. //
  277. // Open the key on the local machine.
  278. //
  279. Status = RegOpenKeyEx(Parent->hKey,
  280. lpSubKey,
  281. 0,
  282. samDesired,
  283. &Key->hKey);
  284. if (Status != ERROR_SUCCESS) {
  285. goto FnExit;
  286. }
  287. //
  288. // Create the key name. only append a trailing backslash
  289. // if a parent name and subkey are non-null
  290. //
  291. lstrcpyW(Key->Name, Parent->Name);
  292. if ((Key->Name[0] != UNICODE_NULL) && (lpSubKey[0] != UNICODE_NULL)) {
  293. lstrcatW(Key->Name, L"\\");
  294. }
  295. lstrcatW(Key->Name, lpSubKey);
  296. Key->GrantedAccess = samDesired;
  297. EnterCriticalSection(&KeyLock);
  298. InsertHeadList(&KeyList, &Key->ListEntry);
  299. InitializeListHead(&Key->NotifyList);
  300. LeaveCriticalSection(&KeyLock);
  301. FnExit:
  302. RELEASE_LOCK(gLockDmpRoot);
  303. if (Status != ERROR_SUCCESS)
  304. {
  305. if (Key) LocalFree(Key);
  306. SetLastError(Status);
  307. return(NULL);
  308. }
  309. else
  310. return((HDMKEY)Key);
  311. }
  312. DWORD
  313. DmEnumKey(
  314. IN HDMKEY hKey,
  315. IN DWORD dwIndex,
  316. OUT LPWSTR lpName,
  317. IN OUT LPDWORD lpcbName,
  318. OUT OPTIONAL PFILETIME lpLastWriteTime
  319. )
  320. /*++
  321. Routine Description:
  322. Enumerates the subkeys of a cluster registry key.
  323. Arguments:
  324. hKey - Supplies the registry key for which the subkeys should
  325. be enumerated.
  326. dwIndex - Supplies the index to be enumerated.
  327. KeyName - Returns the name of the dwIndex subkey. The memory
  328. allocated for this buffer must be freed by the client.
  329. lpLastWriteTime - Returns the last write time.
  330. Return Value:
  331. ERROR_SUCCESS if successful
  332. Win32 error code otherwise
  333. --*/
  334. {
  335. PDMKEY Key;
  336. DWORD Status;
  337. FILETIME LastTime;
  338. Key = (PDMKEY)hKey;
  339. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  340. //check if the key was deleted and invalidated
  341. if (ISKEYDELETED(Key))
  342. {
  343. Status = ERROR_KEY_DELETED;
  344. goto FnExit;
  345. }
  346. Status = RegEnumKeyExW(Key->hKey,
  347. dwIndex,
  348. lpName,
  349. lpcbName,
  350. NULL,
  351. NULL,
  352. NULL,
  353. &LastTime);
  354. if (lpLastWriteTime != NULL) {
  355. *lpLastWriteTime = LastTime;
  356. }
  357. FnExit:
  358. RELEASE_LOCK(gLockDmpRoot);
  359. return(Status);
  360. }
  361. DWORD
  362. DmSetValue(
  363. IN HDMKEY hKey,
  364. IN LPCWSTR lpValueName,
  365. IN DWORD dwType,
  366. IN CONST BYTE *lpData,
  367. IN DWORD cbData
  368. )
  369. /*++
  370. Routine Description:
  371. This routine sets the named value for the specified
  372. cluster registry key.
  373. Arguments:
  374. hKey - Supplies the cluster registry subkey whose value is to be set
  375. lpValueName - Supplies the name of the value to be set.
  376. dwType - Supplies the value data type
  377. lpData - Supplies a pointer to the value data
  378. cbData - Supplies the length of the value data.
  379. Return Value:
  380. ERROR_SUCCESS if successful
  381. Win32 error code otherwise
  382. --*/
  383. {
  384. DWORD Status= ERROR_SUCCESS; //initialize to success
  385. PDMKEY Key;
  386. DWORD NameLength;
  387. DWORD ValueNameLength;
  388. DWORD UpdateLength;
  389. PDM_SET_VALUE_UPDATE Update;
  390. PUCHAR Dest;
  391. Key = (PDMKEY)hKey;
  392. if (ISKEYDELETED(Key))
  393. return(ERROR_KEY_DELETED);
  394. //
  395. // round lengths such that pointers to the data trailing the structure are
  396. // aligned on the architecture's natural boundary
  397. //
  398. NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
  399. NameLength = ROUND_UP_COUNT( NameLength, sizeof( DWORD_PTR ));
  400. ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
  401. ValueNameLength = ROUND_UP_COUNT( ValueNameLength, sizeof( DWORD_PTR ));
  402. UpdateLength = sizeof(DM_SET_VALUE_UPDATE) +
  403. NameLength +
  404. ValueNameLength +
  405. cbData;
  406. Update = (PDM_SET_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  407. if (Update == NULL) {
  408. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  409. return(ERROR_NOT_ENOUGH_MEMORY);
  410. }
  411. Update->lpStatus = &Status;
  412. Update->NameOffset = FIELD_OFFSET(DM_SET_VALUE_UPDATE, KeyName)+NameLength;
  413. Update->DataOffset = Update->NameOffset + ValueNameLength;
  414. Update->DataLength = cbData;
  415. Update->Type = dwType;
  416. CopyMemory(Update->KeyName, Key->Name, NameLength);
  417. Dest = (PUCHAR)Update + Update->NameOffset;
  418. CopyMemory(Dest, lpValueName, ValueNameLength);
  419. Dest = (PUCHAR)Update + Update->DataOffset;
  420. CopyMemory(Dest, lpData, cbData);
  421. Status = GumSendUpdate(GumUpdateRegistry,
  422. DmUpdateSetValue,
  423. UpdateLength,
  424. Update);
  425. LocalFree(Update);
  426. return(Status);
  427. }
  428. DWORD
  429. DmDeleteValue(
  430. IN HDMKEY hKey,
  431. IN LPCWSTR lpValueName
  432. )
  433. /*++
  434. Routine Description:
  435. Removes the specified value from a given registry subkey
  436. Arguments:
  437. hKey - Supplies the key whose value is to be deleted.
  438. lpValueName - Supplies the name of the value to be removed.
  439. Return Value:
  440. If the function succeeds, the return value is ERROR_SUCCESS.
  441. If the function fails, the return value is an error value.
  442. --*/
  443. {
  444. PDMKEY Key;
  445. DWORD NameLength;
  446. DWORD ValueNameLength;
  447. DWORD UpdateLength;
  448. PDM_DELETE_VALUE_UPDATE Update;
  449. PUCHAR Dest;
  450. DWORD Status;
  451. Key = (PDMKEY)hKey;
  452. if (ISKEYDELETED(Key))
  453. return(ERROR_KEY_DELETED);
  454. //
  455. // round up length to align pointer to ValueName on natural architecture
  456. // boundary
  457. //
  458. NameLength = (lstrlenW(Key->Name)+1)*sizeof(WCHAR);
  459. NameLength = ROUND_UP_COUNT( NameLength, sizeof( DWORD_PTR ));
  460. ValueNameLength = (lstrlenW(lpValueName)+1)*sizeof(WCHAR);
  461. UpdateLength = sizeof(DM_DELETE_VALUE_UPDATE) +
  462. NameLength +
  463. ValueNameLength;
  464. Update = (PDM_DELETE_VALUE_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  465. if (Update == NULL) {
  466. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  467. return(ERROR_NOT_ENOUGH_MEMORY);
  468. }
  469. Update->lpStatus = &Status;
  470. Update->NameOffset = FIELD_OFFSET(DM_DELETE_VALUE_UPDATE, KeyName)+NameLength;
  471. CopyMemory(Update->KeyName, Key->Name, NameLength);
  472. Dest = (PUCHAR)Update + Update->NameOffset;
  473. CopyMemory(Dest, lpValueName, ValueNameLength);
  474. Status = GumSendUpdate(GumUpdateRegistry,
  475. DmUpdateDeleteValue,
  476. UpdateLength,
  477. Update);
  478. LocalFree(Update);
  479. return(Status);
  480. }
  481. DWORD
  482. DmQueryValue(
  483. IN HDMKEY hKey,
  484. IN LPCWSTR lpValueName,
  485. OUT LPDWORD lpType,
  486. OUT LPBYTE lpData,
  487. IN OUT LPDWORD lpcbData
  488. )
  489. /*++
  490. Routine Description:
  491. Queries a named value for the specified cluster registry subkey
  492. Arguments:
  493. hKey - Supplies the subkey whose value should be queried
  494. lpValueName - Supplies the named value to be queried
  495. lpType - Returns the type of the value's data
  496. lpData - Returns the value's data
  497. lpcbData - Supplies the size (in bytes) of the lpData buffer
  498. Returns the number of bytes copied into the lpData buffer
  499. If lpData==NULL, cbData is set to the required buffer
  500. size and the function returns ERROR_SUCCESS
  501. Return Value:
  502. ERROR_SUCCESS if successful
  503. Win32 error code otherwise
  504. --*/
  505. {
  506. PDMKEY Key;
  507. DWORD Status;
  508. Key = (PDMKEY)hKey;
  509. //check if the key was deleted and invalidated
  510. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  511. if (ISKEYDELETED(Key))
  512. {
  513. Status = ERROR_KEY_DELETED;
  514. goto FnExit;
  515. }
  516. Status = RegQueryValueEx(Key->hKey,
  517. lpValueName,
  518. NULL,
  519. lpType,
  520. lpData,
  521. lpcbData);
  522. FnExit:
  523. RELEASE_LOCK(gLockDmpRoot);
  524. return(Status);
  525. }
  526. DWORD
  527. DmQueryDword(
  528. IN HDMKEY hKey,
  529. IN LPCWSTR lpValueName,
  530. OUT LPDWORD lpValue,
  531. IN LPDWORD lpDefaultValue OPTIONAL
  532. )
  533. /*++
  534. Routine Description:
  535. Reads a REG_DWORD registry value. If the value is not present, then
  536. default to the value supplied in lpDefaultValue (if present).
  537. Arguments:
  538. hKey - Open key for the value to be read.
  539. lpValueName - Unicode name of the value to be read.
  540. lpValue - Pointer to the DWORD into which to read the value.
  541. lpDefaultValue - Optional pointer to a DWORD to use as a default value.
  542. Return Value:
  543. ERROR_SUCCESS if successful
  544. Win32 error code otherwise
  545. --*/
  546. {
  547. PDMKEY Key;
  548. DWORD Status;
  549. DWORD ValueType;
  550. DWORD ValueSize = sizeof(DWORD);
  551. Key = (PDMKEY)hKey;
  552. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  553. //make sure the key wasnt deleted/invalidated/reopened while we had a
  554. //handle open to it
  555. if (ISKEYDELETED(Key))
  556. {
  557. Status = ERROR_KEY_DELETED;
  558. goto FnExit;
  559. }
  560. Status = RegQueryValueEx(Key->hKey,
  561. lpValueName,
  562. NULL,
  563. &ValueType,
  564. (LPBYTE)lpValue,
  565. &ValueSize);
  566. if ( Status == ERROR_SUCCESS ) {
  567. if ( ValueType != REG_DWORD ) {
  568. Status = ERROR_INVALID_PARAMETER;
  569. }
  570. } else {
  571. if ( ARGUMENT_PRESENT( lpDefaultValue ) ) {
  572. *lpValue = *lpDefaultValue;
  573. Status = ERROR_SUCCESS;
  574. }
  575. }
  576. FnExit:
  577. RELEASE_LOCK(gLockDmpRoot);
  578. return(Status);
  579. } // DmQueryDword
  580. DWORD
  581. DmQueryString(
  582. IN HDMKEY Key,
  583. IN LPCWSTR ValueName,
  584. IN DWORD ValueType,
  585. IN LPWSTR *StringBuffer,
  586. IN OUT LPDWORD StringBufferSize,
  587. OUT LPDWORD StringSize
  588. )
  589. /*++
  590. Routine Description:
  591. Reads a REG_SZ or REG_MULTI_SZ registry value. If the StringBuffer is
  592. not large enough to hold the data, it is reallocated.
  593. Arguments:
  594. Key - Open key for the value to be read.
  595. ValueName - Unicode name of the value to be read.
  596. ValueType - REG_SZ or REG_MULTI_SZ.
  597. StringBuffer - Buffer into which to place the value data.
  598. StringBufferSize - Pointer to the size of the StringBuffer. This parameter
  599. is updated if StringBuffer is reallocated.
  600. StringSize - The size of the data returned in StringBuffer, including
  601. the terminating null character.
  602. Return Value:
  603. The status of the registry query.
  604. --*/
  605. {
  606. DWORD status;
  607. DWORD valueType;
  608. WCHAR *temp;
  609. DWORD oldBufferSize = *StringBufferSize;
  610. BOOL noBuffer = FALSE;
  611. if (*StringBufferSize == 0) {
  612. noBuffer = TRUE;
  613. }
  614. *StringSize = *StringBufferSize;
  615. status = DmQueryValue( Key,
  616. ValueName,
  617. &valueType,
  618. (LPBYTE) *StringBuffer,
  619. StringSize
  620. );
  621. if (status == NO_ERROR) {
  622. if (!noBuffer ) {
  623. if (valueType == ValueType) {
  624. return(NO_ERROR);
  625. }
  626. else {
  627. return(ERROR_INVALID_PARAMETER);
  628. }
  629. }
  630. if (*StringSize) status = ERROR_MORE_DATA;
  631. }
  632. if (status == ERROR_MORE_DATA) {
  633. temp = LocalAlloc(LMEM_FIXED, *StringSize);
  634. if (temp == NULL) {
  635. *StringSize = 0;
  636. return(ERROR_NOT_ENOUGH_MEMORY);
  637. }
  638. if (!noBuffer) {
  639. LocalFree(*StringBuffer);
  640. }
  641. *StringBuffer = temp;
  642. *StringBufferSize = *StringSize;
  643. status = DmQueryValue( Key,
  644. ValueName,
  645. &valueType,
  646. (LPBYTE) *StringBuffer,
  647. StringSize
  648. );
  649. if (status == NO_ERROR) {
  650. if (valueType == ValueType) {
  651. return(NO_ERROR);
  652. }
  653. else {
  654. *StringSize = 0;
  655. return(ERROR_INVALID_PARAMETER);
  656. }
  657. }
  658. }
  659. return(status);
  660. } // DmQueryString
  661. VOID
  662. DmEnumKeys(
  663. IN HDMKEY RootKey,
  664. IN PENUM_KEY_CALLBACK Callback,
  665. IN PVOID Context
  666. )
  667. /*++
  668. Routine Description:
  669. Enumerates the subkeys of the given registry key. For each
  670. subkey, a string is allocated to hold the subkey name and
  671. the subkey is opened. The specified callback function is
  672. called and passed the subkey handle and subkey name.
  673. The callback function is responsible for closing the subkey
  674. handle and freeing the subkey name.
  675. Arguments:
  676. RootKey - Supplies a handle to the key whose subkeys are to
  677. be enumerated.
  678. Callback - Supplies the callback routine.
  679. Context - Supplies an arbitrary context to be passed to the
  680. callback routine.
  681. Return Value:
  682. None.
  683. --*/
  684. {
  685. PWSTR KeyName;
  686. HDMKEY SubKey;
  687. DWORD Index;
  688. DWORD Status;
  689. FILETIME FileTime;
  690. PWSTR NameBuf;
  691. DWORD NameBufSize;
  692. DWORD OrigNameBufSize;
  693. //
  694. // Find the length of the longest subkey name.
  695. //
  696. Status = DmQueryInfoKey(RootKey,
  697. NULL,
  698. &NameBufSize,
  699. NULL,
  700. NULL,
  701. NULL,
  702. NULL,
  703. NULL);
  704. if (Status != ERROR_SUCCESS) {
  705. CL_UNEXPECTED_ERROR(Status);
  706. return;
  707. }
  708. NameBufSize = (NameBufSize + 1)*sizeof(WCHAR);
  709. NameBuf = LocalAlloc(LMEM_FIXED, NameBufSize);
  710. if (NameBuf == NULL) {
  711. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  712. }
  713. OrigNameBufSize = NameBufSize;
  714. //
  715. // Enumerate the subkeys
  716. //
  717. Index = 0;
  718. do {
  719. NameBufSize = OrigNameBufSize;
  720. Status = DmEnumKey( RootKey,
  721. Index,
  722. NameBuf,
  723. &NameBufSize,
  724. NULL);
  725. if (Status == ERROR_SUCCESS) {
  726. KeyName = LocalAlloc(LMEM_FIXED, (wcslen(NameBuf)+1)*sizeof(WCHAR));
  727. if (KeyName != NULL) {
  728. wcscpy(KeyName, NameBuf);
  729. //
  730. // Open the key
  731. //
  732. SubKey = DmOpenKey( RootKey,
  733. KeyName,
  734. MAXIMUM_ALLOWED);
  735. if (SubKey == NULL) {
  736. Status = GetLastError();
  737. CL_UNEXPECTED_ERROR(Status);
  738. LocalFree(KeyName);
  739. } else {
  740. (Callback)(SubKey,
  741. KeyName,
  742. Context);
  743. }
  744. } else {
  745. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  746. }
  747. }
  748. Index++;
  749. } while ( Status == ERROR_SUCCESS );
  750. LocalFree(NameBuf);
  751. } // DmEnumKeys
  752. VOID
  753. DmEnumValues(
  754. IN HDMKEY RootKey,
  755. IN PENUM_VALUE_CALLBACK Callback,
  756. IN PVOID Context
  757. )
  758. /*++
  759. Routine Description:
  760. Enumerates the values of the given registry key. For each
  761. value, a string is allocated to hold the value name and a
  762. buffer is allocated to hold its data. The specified callback
  763. function is called and passed the value name and data.
  764. The callback function must not free either the value name
  765. or its buffer. If it needs this data after the callback
  766. returns, it must copy it.
  767. Arguments:
  768. RootKey - Supplies a handle to the key whose values are to
  769. be enumerated.
  770. Callback - Supplies the callback routine.
  771. Context - Supplies an arbitrary context to be passed to the
  772. callback routine.
  773. Return Value:
  774. None.
  775. --*/
  776. {
  777. DWORD Index;
  778. DWORD Status;
  779. PWSTR NameBuf;
  780. DWORD NameBufSize;
  781. DWORD ValueCount;
  782. DWORD MaxValueLen;
  783. DWORD MaxNameLen;
  784. PVOID ValueBuf;
  785. DWORD cbName;
  786. DWORD cbData;
  787. DWORD dwType;
  788. BOOL Continue;
  789. //
  790. // Find the length of the longest value name and data.
  791. //
  792. Status = DmQueryInfoKey(RootKey,
  793. NULL,
  794. NULL,
  795. &ValueCount,
  796. &MaxNameLen,
  797. &MaxValueLen,
  798. NULL,
  799. NULL);
  800. if (Status != ERROR_SUCCESS) {
  801. CL_UNEXPECTED_ERROR(Status);
  802. return;
  803. }
  804. NameBuf = CsAlloc((MaxNameLen+1)*sizeof(WCHAR));
  805. ValueBuf = CsAlloc(MaxValueLen);
  806. //
  807. // Enumerate the values
  808. //
  809. for (Index=0; Index<ValueCount; Index++) {
  810. cbName = MaxNameLen+1;
  811. cbData = MaxValueLen;
  812. Status = DmEnumValue(RootKey,
  813. Index,
  814. NameBuf,
  815. &cbName,
  816. &dwType,
  817. ValueBuf,
  818. &cbData);
  819. if (Status != ERROR_SUCCESS) {
  820. ClRtlLogPrint(LOG_CRITICAL,
  821. "[DM] DmEnumValue for index %1!d! of key %2!ws! failed %3!d!\n",
  822. Index,
  823. ((PDMKEY)(RootKey))->Name,
  824. Status);
  825. } else {
  826. Continue = (Callback)(NameBuf,
  827. ValueBuf,
  828. dwType,
  829. cbData,
  830. Context);
  831. if (!Continue) {
  832. break;
  833. }
  834. }
  835. }
  836. CsFree(NameBuf);
  837. CsFree(ValueBuf);
  838. } // DmEnumValues
  839. DWORD
  840. DmQueryInfoKey(
  841. IN HDMKEY hKey,
  842. OUT LPDWORD SubKeys,
  843. OUT LPDWORD MaxSubKeyLen,
  844. OUT LPDWORD Values,
  845. OUT LPDWORD MaxValueNameLen,
  846. OUT LPDWORD MaxValueLen,
  847. OUT LPDWORD lpcbSecurityDescriptor,
  848. OUT PFILETIME FileTime
  849. )
  850. /*++
  851. Routine Description:
  852. Arguments:
  853. Return Value:
  854. ERROR_SUCCESS if successful
  855. Win32 error code otherwise
  856. --*/
  857. {
  858. PDMKEY Key;
  859. DWORD Ignored;
  860. DWORD Status;
  861. Key = (PDMKEY)hKey;
  862. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  863. //make sure the key wasnt deleted/invalidated/reopened while we had a
  864. //handle open to it
  865. if (ISKEYDELETED(Key))
  866. {
  867. Status = ERROR_KEY_DELETED;
  868. goto FnExit;
  869. }
  870. Status = RegQueryInfoKeyW( Key->hKey,
  871. NULL,
  872. &Ignored,
  873. NULL,
  874. SubKeys,
  875. MaxSubKeyLen,
  876. &Ignored,
  877. Values,
  878. MaxValueNameLen,
  879. MaxValueLen,
  880. lpcbSecurityDescriptor,
  881. FileTime);
  882. FnExit:
  883. RELEASE_LOCK(gLockDmpRoot);
  884. return(Status);
  885. } // DmQueryInfoKey
  886. DWORD
  887. DmDeleteKey(
  888. IN HDMKEY hKey,
  889. IN LPCWSTR lpSubKey
  890. )
  891. /*++
  892. Routine Description:
  893. Deletes the specified key. A key that has subkeys cannot
  894. be deleted.
  895. Arguments:
  896. hKey - Supplies a handle to a currently open key.
  897. lpSubKey - Points to a null-terminated string specifying the
  898. name of the key to delete. This parameter cannot be NULL,
  899. and the specified key must not have subkeys.
  900. Return Value:
  901. If the function succeeds, the return value is ERROR_SUCCESS.
  902. If the function fails, the return value is an error value.
  903. --*/
  904. {
  905. PDMKEY Key;
  906. DWORD NameLength;
  907. DWORD UpdateLength;
  908. PDM_DELETE_KEY_UPDATE Update;
  909. DWORD Status;
  910. Key = (PDMKEY)hKey;
  911. //make sure the key wasnt deleted/invalidated/reopened while we had a
  912. //handle open to it
  913. if (ISKEYDELETED(Key))
  914. return(ERROR_KEY_DELETED);
  915. NameLength = (lstrlenW(Key->Name) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR);
  916. UpdateLength = NameLength + sizeof(DM_DELETE_KEY_UPDATE);
  917. Update = (PDM_DELETE_KEY_UPDATE)LocalAlloc(LMEM_FIXED, UpdateLength);
  918. if (Update == NULL) {
  919. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  920. return(ERROR_NOT_ENOUGH_MEMORY);
  921. }
  922. Update->lpStatus = &Status;
  923. CopyMemory(Update->Name, Key->Name, (lstrlenW(Key->Name) + 1) * sizeof(WCHAR));
  924. if (Update->Name[0] != '\0') {
  925. lstrcatW(Update->Name, L"\\");
  926. }
  927. lstrcatW(Update->Name, lpSubKey);
  928. Status = GumSendUpdate(GumUpdateRegistry,
  929. DmUpdateDeleteKey,
  930. sizeof(DM_DELETE_KEY_UPDATE)+NameLength,
  931. Update);
  932. LocalFree(Update);
  933. return(Status);
  934. }
  935. DWORD
  936. DmDeleteTree(
  937. IN HDMKEY hKey,
  938. IN LPCWSTR lpSubKey
  939. )
  940. /*++
  941. Routine Description:
  942. Deletes the specified registry subtree. All subkeys are
  943. deleted.
  944. Arguments:
  945. hKey - Supplies a handle to a currently open key.
  946. lpSubKey - Points to a null-terminated string specifying the
  947. name of the key to delete. This parameter cannot be NULL.
  948. Any subkeys of the specified key will also be deleted.
  949. Return Value:
  950. If the function succeeds, the return value is ERROR_SUCCESS.
  951. If the function fails, the return value is an error value.
  952. --*/
  953. {
  954. HDMKEY Subkey;
  955. DWORD i;
  956. DWORD Status;
  957. LPWSTR KeyBuffer=NULL;
  958. DWORD MaxKeyLen;
  959. DWORD NeededSize;
  960. Subkey = DmOpenKey(hKey,
  961. lpSubKey,
  962. MAXIMUM_ALLOWED);
  963. if (Subkey == NULL) {
  964. Status = GetLastError();
  965. return(Status);
  966. }
  967. //
  968. // Get the size of name buffer we will need.
  969. //
  970. Status = DmQueryInfoKey(Subkey,
  971. NULL,
  972. &MaxKeyLen,
  973. NULL,
  974. NULL,
  975. NULL,
  976. NULL,
  977. NULL);
  978. if (Status != ERROR_SUCCESS) {
  979. CL_UNEXPECTED_ERROR( Status );
  980. DmCloseKey(Subkey);
  981. return(Status);
  982. }
  983. KeyBuffer = LocalAlloc(LMEM_FIXED, (MaxKeyLen+1)*sizeof(WCHAR));
  984. if (KeyBuffer == NULL) {
  985. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  986. DmCloseKey(Subkey);
  987. return(ERROR_NOT_ENOUGH_MEMORY);
  988. }
  989. //
  990. // Enumerate the subkeys and apply ourselves recursively to each one.
  991. //
  992. i=0;
  993. do {
  994. NeededSize = MaxKeyLen+1;
  995. Status = DmEnumKey(Subkey,
  996. i,
  997. KeyBuffer,
  998. &NeededSize,
  999. NULL);
  1000. if (Status == ERROR_SUCCESS) {
  1001. //
  1002. // Call ourselves recursively on this keyname.
  1003. //
  1004. DmDeleteTree(Subkey, KeyBuffer);
  1005. } else {
  1006. //
  1007. // Some odd error, keep going with the next key.
  1008. //
  1009. ++i;
  1010. }
  1011. } while ( Status != ERROR_NO_MORE_ITEMS );
  1012. DmCloseKey(Subkey);
  1013. Status = DmDeleteKey(hKey, lpSubKey);
  1014. if (KeyBuffer != NULL) {
  1015. LocalFree(KeyBuffer);
  1016. }
  1017. return(Status);
  1018. }
  1019. DWORD
  1020. DmEnumValue(
  1021. IN HDMKEY hKey,
  1022. IN DWORD dwIndex,
  1023. OUT LPWSTR lpValueName,
  1024. IN OUT LPDWORD lpcbValueName,
  1025. OUT LPDWORD lpType,
  1026. OUT LPBYTE lpData,
  1027. IN OUT LPDWORD lpcbData
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Enumerates the specified value of a registry subkey
  1032. Arguments:
  1033. hKey - Supplies the registry key handle
  1034. dwIndex - Supplies the index of the value to be enumerated
  1035. lpValueName - Points to a buffer that receives the name of the value,
  1036. including the terminating null character
  1037. lpcbValueName - Points to a variable that specifies the size, in characters,
  1038. of the buffer pointed to by the lpValueName parameter. This size should
  1039. include the terminating null character. When the function returns, the
  1040. variable pointed to by lpcbValueName contains the number of characters
  1041. stored in the buffer. The count returned does not include the terminating
  1042. null character.
  1043. lpType - Returns the value data type
  1044. lpData - Points to a buffer that receives the data for the value entry. This
  1045. parameter can be NULL if the data is not required.
  1046. lpcbData - Points to a variable that specifies the size, in bytes, of the
  1047. buffer pointed to by the lpData parameter. When the function returns, the
  1048. variable pointed to by the lpcbData parameter contains the number of bytes
  1049. stored in the buffer. This parameter can be NULL, only if lpData is NULL.
  1050. Return Value:
  1051. If the function succeeds, the return value is ERROR_SUCCESS.
  1052. If the function fails, the return value is an error value.
  1053. --*/
  1054. {
  1055. PDMKEY Key;
  1056. DWORD Status;
  1057. DWORD cbValueName = *lpcbValueName;
  1058. Key = (PDMKEY)hKey;
  1059. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  1060. //make sure the key wasnt deleted/invalidated/reopened while we had a
  1061. //handle open to it
  1062. if (ISKEYDELETED(Key))
  1063. {
  1064. Status = ERROR_KEY_DELETED;
  1065. goto FnExit;
  1066. }
  1067. Status = RegEnumValueW(Key->hKey,
  1068. dwIndex,
  1069. lpValueName,
  1070. lpcbValueName,
  1071. NULL,
  1072. lpType,
  1073. lpData,
  1074. lpcbData);
  1075. //
  1076. // The following code is to mask the registry behavior by which RegEnumValue does not necessarily
  1077. // fill in lpValueName (even though we specify a large enough buffer) when lpData buffer is a
  1078. // valid buffer but a little too small.
  1079. //
  1080. if ( Status == ERROR_MORE_DATA )
  1081. {
  1082. DWORD dwError;
  1083. dwError = RegEnumValueW( Key->hKey,
  1084. dwIndex,
  1085. lpValueName,
  1086. &cbValueName,
  1087. NULL,
  1088. NULL,
  1089. NULL,
  1090. NULL );
  1091. if ( ( dwError != ERROR_SUCCESS ) &&
  1092. ( dwError != ERROR_MORE_DATA ) )
  1093. {
  1094. Status = dwError;
  1095. } else
  1096. {
  1097. *lpcbValueName = cbValueName;
  1098. }
  1099. }
  1100. FnExit:
  1101. RELEASE_LOCK(gLockDmpRoot);
  1102. return(Status);
  1103. }
  1104. DWORD
  1105. DmAppendToMultiSz(
  1106. IN HDMKEY hKey,
  1107. IN LPCWSTR lpValueName,
  1108. IN LPCWSTR lpString
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. Adds another string to a REG_MULTI_SZ value. If the value does
  1113. not exist, it will be created.
  1114. Arguments:
  1115. hKey - Supplies the key where the value exists. This key must
  1116. have been opened with KEY_READ | KEY_SET_VALUE access
  1117. lpValueName - Supplies the name of the value.
  1118. lpString - Supplies the string to be appended to the REG_MULTI_SZ value
  1119. Return Value:
  1120. ERROR_SUCCESS if successful
  1121. Win32 error code otherwise
  1122. --*/
  1123. {
  1124. DWORD ValueLength = 512;
  1125. DWORD ReturnedLength;
  1126. LPWSTR ValueData;
  1127. DWORD StringLength;
  1128. DWORD Status;
  1129. DWORD cbValueData;
  1130. PWSTR s;
  1131. DWORD Type;
  1132. StringLength = (lstrlenW(lpString)+1)*sizeof(WCHAR);
  1133. retry:
  1134. ValueData = LocalAlloc(LMEM_FIXED, ValueLength + StringLength);
  1135. if (ValueData == NULL) {
  1136. return(ERROR_NOT_ENOUGH_MEMORY);
  1137. }
  1138. cbValueData = ValueLength;
  1139. Status = DmQueryValue(hKey,
  1140. lpValueName,
  1141. &Type,
  1142. (LPBYTE)ValueData,
  1143. &cbValueData);
  1144. if (Status == ERROR_MORE_DATA) {
  1145. //
  1146. // The existing value is too large for our buffer.
  1147. // Retry with a larger buffer.
  1148. //
  1149. ValueLength = cbValueData;
  1150. LocalFree(ValueData);
  1151. goto retry;
  1152. }
  1153. if (Status == ERROR_FILE_NOT_FOUND) {
  1154. //
  1155. // The value does not currently exist. Create the
  1156. // value with our data.
  1157. //
  1158. s = ValueData;
  1159. } else if (Status == ERROR_SUCCESS) {
  1160. //
  1161. // A value already exists. Append our string to the
  1162. // MULTI_SZ.
  1163. //
  1164. s = (PWSTR)((PCHAR)ValueData + cbValueData) - 1;
  1165. } else {
  1166. LocalFree(ValueData);
  1167. return(Status);
  1168. }
  1169. CopyMemory(s, lpString, StringLength);
  1170. s += (StringLength / sizeof(WCHAR));
  1171. *s++ = L'\0';
  1172. Status = DmSetValue(hKey,
  1173. lpValueName,
  1174. REG_MULTI_SZ,
  1175. (CONST BYTE *)ValueData,
  1176. (DWORD)((s-ValueData)*sizeof(WCHAR)));
  1177. LocalFree(ValueData);
  1178. return(Status);
  1179. }
  1180. DWORD
  1181. DmRemoveFromMultiSz(
  1182. IN HDMKEY hKey,
  1183. IN LPCWSTR lpValueName,
  1184. IN LPCWSTR lpString
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. Removes a string from a REG_MULTI_SZ value.
  1189. Arguments:
  1190. hKey - Supplies the key where the value exists. This key must
  1191. have been opened with READ | KEY_SET_VALUE access
  1192. lpValueName - Supplies the name of the value.
  1193. lpString - Supplies the string to be removed from the REG_MULTI_SZ value
  1194. Return Value:
  1195. ERROR_SUCCESS if successful
  1196. Win32 error code otherwise
  1197. --*/
  1198. {
  1199. DWORD Status;
  1200. LPWSTR Buffer=NULL;
  1201. DWORD BufferSize;
  1202. DWORD DataSize;
  1203. LPWSTR Current;
  1204. DWORD CurrentLength;
  1205. DWORD i;
  1206. LPWSTR Next;
  1207. PCHAR Src, Dest;
  1208. DWORD NextLength;
  1209. DWORD MultiLength;
  1210. BufferSize = 0;
  1211. Status = DmQueryString(hKey,
  1212. lpValueName,
  1213. REG_MULTI_SZ,
  1214. &Buffer,
  1215. &BufferSize,
  1216. &DataSize);
  1217. if (Status != ERROR_SUCCESS) {
  1218. goto FnExit;
  1219. }
  1220. MultiLength = DataSize/sizeof(WCHAR);
  1221. Status = ClRtlMultiSzRemove(Buffer,
  1222. &MultiLength,
  1223. lpString);
  1224. if (Status == ERROR_SUCCESS) {
  1225. //
  1226. // Set the new value back.
  1227. //
  1228. Status = DmSetValue(hKey,
  1229. lpValueName,
  1230. REG_MULTI_SZ,
  1231. (CONST BYTE *)Buffer,
  1232. MultiLength * sizeof(WCHAR));
  1233. } else if (Status == ERROR_FILE_NOT_FOUND) {
  1234. Status = ERROR_SUCCESS;
  1235. }
  1236. FnExit:
  1237. if (Buffer) LocalFree(Buffer);
  1238. return(Status);
  1239. }
  1240. DWORD
  1241. DmGetKeySecurity(
  1242. IN HDMKEY hKey,
  1243. IN SECURITY_INFORMATION RequestedInformation,
  1244. OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1245. IN LPDWORD lpcbSecurityDescriptor
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. Retrieves a copy of the security descriptor protecting
  1250. the specified cluster registry key.
  1251. Arguments:
  1252. hKey - Supplies the handle of the key
  1253. RequestedInformation - Specifies a SECURITY_INFORMATION structure that
  1254. indicates the requested security information.
  1255. pSecurityDescriptor - Points to a buffer that receives a copy of the
  1256. requested security descriptor.
  1257. lpcbSecurityDescriptor - Points to a variable that specifies the size,
  1258. in bytes, of the buffer pointed to by the pSecurityDescriptor parameter.
  1259. When the function returns, the variable contains the number of bytes
  1260. written to the buffer.
  1261. Return Value:
  1262. ERROR_SUCCESS if successful
  1263. Win32 error code otherwise
  1264. --*/
  1265. {
  1266. DWORD Status;
  1267. PDMKEY Key = (PDMKEY)hKey;
  1268. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  1269. //make sure the key wasnt deleted/invalidated/reopened while we had a
  1270. //handle open to it
  1271. if (ISKEYDELETED(Key))
  1272. {
  1273. Status = ERROR_KEY_DELETED;
  1274. goto FnExit;
  1275. }
  1276. Status = RegGetKeySecurity(Key->hKey,
  1277. RequestedInformation,
  1278. pSecurityDescriptor,
  1279. lpcbSecurityDescriptor);
  1280. FnExit:
  1281. RELEASE_LOCK(gLockDmpRoot);
  1282. return(Status);
  1283. }
  1284. DWORD
  1285. DmSetKeySecurity(
  1286. IN HDMKEY hKey,
  1287. IN SECURITY_INFORMATION SecurityInformation,
  1288. IN PSECURITY_DESCRIPTOR pSecurityDescriptor
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. Sets the security on the specified registry key.
  1293. Arguments:
  1294. hKey - Supplies a handle to a currently open key.
  1295. SecurityInformation - Supplies the type of security information to
  1296. be set.
  1297. pRpcSecurityDescriptor - Supplies the security information
  1298. Return Value:
  1299. ERROR_SUCCESS if successful
  1300. Win32 error code otherwise
  1301. --*/
  1302. {
  1303. DWORD Status;
  1304. PDMKEY Key = (PDMKEY)hKey;
  1305. //make sure the key wasnt deleted/invalidated/reopened while we had a
  1306. //handle open to it
  1307. if (ISKEYDELETED(Key))
  1308. return(ERROR_KEY_DELETED);
  1309. Status = GumSendUpdateEx(GumUpdateRegistry,
  1310. DmUpdateSetSecurity,
  1311. 4,
  1312. sizeof(SecurityInformation),
  1313. &SecurityInformation,
  1314. (lstrlenW(Key->Name)+1)*sizeof(WCHAR),
  1315. Key->Name,
  1316. GetSecurityDescriptorLength(pSecurityDescriptor),
  1317. pSecurityDescriptor,
  1318. sizeof(Key->GrantedAccess),
  1319. &Key->GrantedAccess);
  1320. return(Status);
  1321. }
  1322. DWORD
  1323. DmCommitRegistry(
  1324. VOID
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. Flushes the registry to disk, producing a new persistent cluster registry state.
  1329. Arguments:
  1330. None
  1331. Return Value:
  1332. ERROR_SUCCESS if successful
  1333. Win32 error code otherwise
  1334. --*/
  1335. {
  1336. DWORD Status;
  1337. ACQUIRE_SHARED_LOCK(gLockDmpRoot);
  1338. Status = RegFlushKey(DmpRoot);
  1339. RELEASE_LOCK(gLockDmpRoot);
  1340. if (Status != ERROR_SUCCESS) {
  1341. ClRtlLogPrint(LOG_CRITICAL,
  1342. "[DM] DmCommitRegistry failed to flush dirty data %1!d!\n",
  1343. Status);
  1344. }
  1345. return(Status);
  1346. }
  1347. DWORD
  1348. DmRollbackRegistry(
  1349. VOID
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. Rolls the registry back to the last previously committed state.
  1354. Arguments:
  1355. None
  1356. Return Value:
  1357. ERROR_SUCCESS if successful
  1358. Win32 error code otherwise
  1359. --*/
  1360. {
  1361. DWORD Status;
  1362. BOOLEAN WasEnabled;
  1363. ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
  1364. //hold the key lock as well
  1365. EnterCriticalSection(&KeyLock);
  1366. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  1367. &WasEnabled);
  1368. if (Status != ERROR_SUCCESS)
  1369. {
  1370. ClRtlLogPrint(LOG_CRITICAL,
  1371. "[DM] DmRollbackRegistry failed to restore privilege %1!d!\n",
  1372. Status);
  1373. goto FnExit;
  1374. }
  1375. //
  1376. // Restart the registry watcher thread so it is not trying to use
  1377. // DmpRoot while we are messing with things.
  1378. //
  1379. DmpRestartFlusher();
  1380. //
  1381. // Close any open handles
  1382. //
  1383. DmpInvalidateKeys();
  1384. Status = NtRestoreKey(DmpRoot,
  1385. NULL,
  1386. REG_REFRESH_HIVE);
  1387. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  1388. WasEnabled);
  1389. if (Status != ERROR_SUCCESS)
  1390. {
  1391. ClRtlLogPrint(LOG_CRITICAL,
  1392. "[DM] DmRollbackRegistry: NtRestoreKey failed %1!d!\n",
  1393. Status);
  1394. goto FnExit;
  1395. }
  1396. //
  1397. // Reopen handles
  1398. //
  1399. RegCloseKey(DmpRoot);
  1400. Status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  1401. DmpClusterParametersKeyName,
  1402. &DmpRoot);
  1403. if (Status != ERROR_SUCCESS)
  1404. {
  1405. ClRtlLogPrint(LOG_CRITICAL,
  1406. "[DM] DmRollbackRegistry failed to reopen DmpRoot %1!d!\n",
  1407. Status);
  1408. goto FnExit;
  1409. }
  1410. DmpReopenKeys();
  1411. FnExit:
  1412. //release the locks
  1413. LeaveCriticalSection(&KeyLock);
  1414. RELEASE_LOCK(gLockDmpRoot);
  1415. if (Status != ERROR_SUCCESS)
  1416. {
  1417. ClRtlLogPrint(LOG_CRITICAL,
  1418. "[DM] DmRollbackRegistry failed to flush dirty data %1!d!\n",
  1419. Status);
  1420. }
  1421. return(Status);
  1422. }
  1423. DWORD
  1424. DmRtlCreateKey(
  1425. IN HDMKEY hKey,
  1426. IN LPCWSTR lpSubKey,
  1427. IN DWORD dwOptions,
  1428. IN DWORD samDesired,
  1429. IN OPTIONAL LPVOID lpSecurityDescriptor,
  1430. OUT HDMKEY * phkResult,
  1431. OUT LPDWORD lpDisposition
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. Wrapper function for DmCreateKey. Its definition corresponds to
  1436. ClusterRegCreateKey. This should be used instead of DmCreateKey
  1437. when passing to ClRtl* funtions.
  1438. --*/
  1439. {
  1440. DWORD status;
  1441. *phkResult = DmCreateKey(
  1442. hKey,
  1443. lpSubKey,
  1444. dwOptions,
  1445. samDesired,
  1446. lpSecurityDescriptor,
  1447. lpDisposition
  1448. );
  1449. if (*phkResult == NULL)
  1450. status=GetLastError();
  1451. else
  1452. status = ERROR_SUCCESS;
  1453. return status;
  1454. }
  1455. DWORD
  1456. DmRtlOpenKey(
  1457. IN HDMKEY hKey,
  1458. IN LPCWSTR lpSubKey,
  1459. IN DWORD samDesired,
  1460. OUT HDMKEY * phkResult
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. Wrapper function for DmOpenKey. Its definition corresponds to
  1465. ClusterRegOpenKey. This should be used instead of DmOpenKey when
  1466. passing to ClRtl* funtions. See DmOpenKey for argument description
  1467. --*/
  1468. {
  1469. DWORD status;
  1470. *phkResult = DmOpenKey(
  1471. hKey,
  1472. lpSubKey,
  1473. samDesired
  1474. );
  1475. if (*phkResult == NULL)
  1476. status=GetLastError();
  1477. else
  1478. status=ERROR_SUCCESS;
  1479. return status;
  1480. }