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.

1926 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999 - 2000.
  5. //
  6. // File: registry.cpp
  7. //
  8. // Contents: NtMarta registry functions
  9. //
  10. // History: 4/99 philh Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. extern "C" {
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. }
  20. #include <windows.h>
  21. #include <kernel.h>
  22. #include <assert.h>
  23. #include <ntstatus.h>
  24. #include <memory.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <time.h>
  29. #include <stddef.h>
  30. #include <registry.h>
  31. #include <wow64reg.h>
  32. #ifdef STATIC
  33. #undef STATIC
  34. #endif
  35. #define STATIC
  36. // Registry object names returned by NtQueryObject are prefixed by
  37. // the following
  38. #define REG_OBJ_TAG L"\\REGISTRY\\"
  39. #define REG_OBJ_TAG_LEN (sizeof(REG_OBJ_TAG) / sizeof(WCHAR) - 1)
  40. //+-------------------------------------------------------------------------
  41. // Registry Context data structures
  42. //--------------------------------------------------------------------------
  43. typedef struct _REG_FIND_DATA REG_FIND_DATA, *PREG_FIND_DATA;
  44. typedef struct _REG_CONTEXT {
  45. DWORD dwRefCnt;
  46. DWORD dwFlags;
  47. // Only closed when REG_CONTEXT_CLOSE_HKEY_FLAG is set
  48. HKEY hKey;
  49. LPWSTR pwszObject; // optional, allocated
  50. // Following is allocated and updated for FindFirst, FindNext
  51. PREG_FIND_DATA pRegFindData;
  52. } REG_CONTEXT, *PREG_CONTEXT;
  53. #define REG_CONTEXT_CLOSE_HKEY_FLAG 0x1
  54. struct _REG_FIND_DATA {
  55. PREG_CONTEXT pRegParentContext; // ref counted
  56. DWORD cSubKeys;
  57. DWORD cchMaxSubKey;
  58. DWORD iSubKey; // index of next FindNext
  59. // Following isn't allocated separately, it follows this data structure
  60. LPWSTR pwszSubKey;
  61. };
  62. //+-------------------------------------------------------------------------
  63. // Registry allocation functions
  64. //--------------------------------------------------------------------------
  65. #define I_MartaRegZeroAlloc(size) \
  66. LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, size)
  67. #define I_MartaRegNonzeroAlloc(size) \
  68. LocalAlloc(LMEM_FIXED, size)
  69. STATIC
  70. inline
  71. VOID
  72. I_MartaRegFree(
  73. IN LPVOID pv
  74. )
  75. {
  76. if (pv)
  77. LocalFree(pv);
  78. }
  79. STATIC
  80. DWORD
  81. I_MartaRegDupString(
  82. IN LPCWSTR pwszOrig,
  83. OUT LPWSTR *ppwszDup
  84. )
  85. /*++
  86. Routine Description:
  87. Allocate memory and copy the given name into it.
  88. Arguments:
  89. pwszOrig - String to be duplicated.
  90. ppwszDup - To return the duplicate.
  91. Return Value:
  92. ERROR_SUCCESS in case of success.
  93. ERROR_NOT_ENOUGH_MEMORY if allocation failed.
  94. --*/
  95. {
  96. DWORD dwErr;
  97. DWORD cchOrig;
  98. LPWSTR pwszDup;
  99. cchOrig = wcslen(pwszOrig);
  100. if (NULL == (pwszDup = (LPWSTR) I_MartaRegNonzeroAlloc(
  101. (cchOrig + 1) * sizeof(WCHAR)))) {
  102. *ppwszDup = NULL;
  103. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  104. } else {
  105. memcpy(pwszDup, pwszOrig, (cchOrig + 1) * sizeof(WCHAR));
  106. *ppwszDup = pwszDup;
  107. dwErr = ERROR_SUCCESS;
  108. }
  109. return dwErr;
  110. }
  111. STATIC
  112. DWORD
  113. I_MartaRegGetParentString(
  114. IN OUT LPWSTR pwszParent
  115. )
  116. /*++
  117. Routine Description:
  118. Given the name for a registry key, get the name of its parent. Does not allocate
  119. memory. Scans till the first '\' from the right and deletes the name after
  120. that.
  121. Arguments:
  122. pwszParent - Object name which will be converted to its parent name.
  123. Return Value:
  124. ERROR_SUCCESS in case of success.
  125. ERROR_* otherwise
  126. --*/
  127. {
  128. DWORD dwErr;
  129. DWORD cch;
  130. LPWSTR pwsz;
  131. if (NULL == pwszParent)
  132. return ERROR_INVALID_NAME;
  133. cch = wcslen(pwszParent);
  134. pwsz = pwszParent + cch;
  135. if (0 == cch)
  136. goto InvalidNameReturn;
  137. pwsz--;
  138. //
  139. // Remove any trailing '\'s
  140. //
  141. while (L'\\' == *pwsz) {
  142. if (pwsz == pwszParent)
  143. goto InvalidNameReturn;
  144. pwsz--;
  145. }
  146. //
  147. // Peal off the last path name component
  148. //
  149. while (L'\\' != *pwsz) {
  150. if (pwsz == pwszParent)
  151. goto InvalidNameReturn;
  152. pwsz--;
  153. }
  154. //
  155. // Remove all trailing '\'s from the parent.
  156. // This could also be the leading '\\'s for a computer name.
  157. //
  158. while (L'\\' == *pwsz) {
  159. if (pwsz == pwszParent)
  160. goto InvalidNameReturn;
  161. pwsz--;
  162. }
  163. pwsz++;
  164. assert(L'\\' == *pwsz);
  165. dwErr = ERROR_SUCCESS;
  166. CommonReturn:
  167. *pwsz = L'\0';
  168. return dwErr;
  169. InvalidNameReturn:
  170. dwErr = ERROR_INVALID_NAME;
  171. goto CommonReturn;
  172. }
  173. STATIC
  174. DWORD
  175. I_MartaRegCreateChildString(
  176. IN LPCWSTR pwszParent,
  177. IN LPCWSTR pwszSubKey,
  178. OUT LPWSTR *ppwszChild
  179. )
  180. /*++
  181. Routine Description:
  182. Given the name of the parent and the name of the subkey, create the full
  183. name of the child.
  184. Arguments:
  185. pwszParent - Name of the parent.
  186. pwszSubKey - Name of the subkey.
  187. ppwszChild - To return the name of the child.
  188. Return Value:
  189. ERROR_SUCCESS in case of success.
  190. ERROR_NOT_ENOUGH_MEMORY if allocation failed.
  191. --*/
  192. {
  193. DWORD dwErr;
  194. DWORD cchParent;
  195. DWORD cchSubKey;
  196. DWORD cchChild;
  197. LPWSTR pwszChild = NULL;
  198. if (NULL == pwszParent || NULL == pwszSubKey)
  199. goto InvalidNameReturn;
  200. cchParent = wcslen(pwszParent);
  201. //
  202. // Remove any trailing '\'s from parent
  203. //
  204. while (0 < cchParent && L'\\' == pwszParent[cchParent - 1])
  205. cchParent--;
  206. if (0 == cchParent)
  207. goto InvalidNameReturn;
  208. cchSubKey = wcslen(pwszSubKey);
  209. if (0 == cchSubKey)
  210. goto InvalidNameReturn;
  211. cchChild = cchParent + 1 + cchSubKey;
  212. if (NULL == (pwszChild = (LPWSTR) I_MartaRegNonzeroAlloc(
  213. (cchChild + 1) * sizeof(WCHAR))))
  214. goto NotEnoughMemoryReturn;
  215. //
  216. // Construct the name of the child from the given strings.
  217. //
  218. memcpy(pwszChild, pwszParent, cchParent * sizeof(WCHAR));
  219. pwszChild[cchParent] = L'\\';
  220. memcpy(pwszChild + cchParent + 1, pwszSubKey, cchSubKey * sizeof(WCHAR));
  221. pwszChild[cchChild] = L'\0';
  222. dwErr = ERROR_SUCCESS;
  223. CommonReturn:
  224. *ppwszChild = pwszChild;
  225. return dwErr;
  226. InvalidNameReturn:
  227. dwErr = ERROR_INVALID_NAME;
  228. goto CommonReturn;
  229. NotEnoughMemoryReturn:
  230. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  231. goto CommonReturn;
  232. }
  233. STATIC
  234. DWORD
  235. I_MartaRegParseName(
  236. IN OUT LPWSTR pwszObject,
  237. OUT LPWSTR *ppwszMachine,
  238. OUT LPWSTR *ppwszRemaining
  239. )
  240. /*++
  241. Routine Description:
  242. Parses a registry object name for the machine name.
  243. Arguments:
  244. pwszObject - the name of the object
  245. ppwszMachine - the machine the object is on
  246. ppwszRemaining - the remaining name after the machine name
  247. Return Value:
  248. ERROR_SUCCESS in case of success.
  249. ERROR_NOT_ENOUGH_MEMORY if allocation failed.
  250. --*/
  251. {
  252. if (pwszObject == wcsstr(pwszObject, L"\\\\")) {
  253. *ppwszMachine = pwszObject + 2;
  254. *ppwszRemaining = wcschr(*ppwszMachine, L'\\');
  255. if (*ppwszRemaining != NULL) {
  256. **ppwszRemaining = L'\0';
  257. *ppwszRemaining += 1;
  258. }
  259. } else {
  260. *ppwszMachine = NULL;
  261. *ppwszRemaining = pwszObject;
  262. }
  263. return ERROR_SUCCESS;
  264. }
  265. STATIC
  266. DWORD
  267. I_MartaRegInitContext(
  268. OUT PREG_CONTEXT *ppRegContext
  269. )
  270. /*++
  271. Routine Description:
  272. Allocate and initialize memory for the context.
  273. Arguments:
  274. ppRegContext - To return the pointer to the allcoated memory.
  275. Return Value:
  276. ERROR_SUCCESS in case of success.
  277. ERROR_* otherwise
  278. --*/
  279. {
  280. DWORD dwErr;
  281. PREG_CONTEXT pRegContext;
  282. if (pRegContext = (PREG_CONTEXT) I_MartaRegZeroAlloc(
  283. sizeof(REG_CONTEXT))) {
  284. pRegContext->dwRefCnt = 1;
  285. dwErr = ERROR_SUCCESS;
  286. } else {
  287. pRegContext = NULL;
  288. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  289. }
  290. *ppRegContext = pRegContext;
  291. return dwErr;
  292. }
  293. DWORD
  294. MartaOpenRegistryKeyNamedObject(
  295. IN LPCWSTR pwszObject,
  296. IN ACCESS_MASK AccessMask,
  297. OUT PMARTA_CONTEXT pContext
  298. )
  299. /*++
  300. Routine Description:
  301. Open the given registry key with desired access mask and return a context
  302. handle.
  303. Arguments:
  304. pwszObject - Name of the registry key which will be opened.
  305. AccessMask - Desired access mask with which the registry key will be opened.
  306. pContext - To return a context handle.
  307. Return Value:
  308. ERROR_SUCCESS in case of success.
  309. ERROR_* otherwise
  310. --*/
  311. {
  312. DWORD dwErr = ERROR_SUCCESS;
  313. PREG_CONTEXT pRegContext = NULL;
  314. LPWSTR pwszDupObject = NULL;
  315. HKEY hKeyRemote = NULL;
  316. HKEY hKeyBase; // not opened, don't close at return
  317. //
  318. // Following aren't allocated
  319. //
  320. LPWSTR pwszMachine, pwszRemaining, pwszBaseKey, pwszSubKey;
  321. if (NULL == pwszObject)
  322. goto InvalidNameReturn;
  323. if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegContext)))
  324. goto ErrorReturn;
  325. //
  326. // Allocate and copy the name into the context
  327. //
  328. if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(pwszObject,
  329. &pRegContext->pwszObject)))
  330. goto ErrorReturn;
  331. //
  332. // Save another copy of the name since we must crack it.
  333. //
  334. if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(pwszObject,
  335. &pwszDupObject)))
  336. goto ErrorReturn;
  337. //
  338. // Get the optional machine name and the remaining name
  339. //
  340. if (ERROR_SUCCESS != (dwErr = I_MartaRegParseName(pwszDupObject,
  341. &pwszMachine, &pwszRemaining)))
  342. goto ErrorReturn;
  343. if (NULL == pwszRemaining)
  344. goto InvalidNameReturn;
  345. //
  346. // Get the base key name and the subkey name
  347. //
  348. pwszBaseKey = pwszRemaining;
  349. pwszSubKey = wcschr(pwszRemaining, L'\\');
  350. if (NULL != pwszSubKey) {
  351. *pwszSubKey = L'\0';
  352. pwszSubKey++;
  353. //
  354. // Advance past any more '\'s separating the BaseKey from the SubKey
  355. //
  356. while (L'\\' == *pwszSubKey)
  357. pwszSubKey++;
  358. }
  359. if (0 == _wcsicmp(pwszBaseKey, L"MACHINE")) {
  360. hKeyBase = HKEY_LOCAL_MACHINE;
  361. } else if (0 == _wcsicmp(pwszBaseKey, L"USERS") ||
  362. 0 == _wcsicmp(pwszBaseKey, L"USER")) {
  363. hKeyBase = HKEY_USERS;
  364. } else if (NULL == pwszMachine) {
  365. //
  366. // these are only valid on the local machine
  367. //
  368. if (0 == _wcsicmp(pwszBaseKey, L"CLASSES_ROOT")) {
  369. hKeyBase = HKEY_CLASSES_ROOT;
  370. } else if (0 == _wcsicmp(pwszBaseKey, L"CURRENT_USER")) {
  371. hKeyBase = HKEY_CURRENT_USER;
  372. } else if (0 == _wcsicmp(pwszBaseKey, L"CONFIG")) {
  373. hKeyBase = HKEY_CURRENT_CONFIG;
  374. } else {
  375. goto InvalidParameterReturn;
  376. }
  377. } else {
  378. goto InvalidParameterReturn;
  379. }
  380. //
  381. // If it is a remote name, connect to that registry
  382. //
  383. if (pwszMachine) {
  384. if (ERROR_SUCCESS != (dwErr = RegConnectRegistryW(
  385. pwszMachine,
  386. hKeyBase,
  387. &hKeyRemote
  388. )))
  389. goto ErrorReturn;
  390. hKeyBase = hKeyRemote;
  391. }
  392. if (NULL == pwszMachine && (NULL == pwszSubKey || L'\0' == *pwszSubKey))
  393. //
  394. // Opening a predefined handle causes the previously opened handle
  395. // to be closed. Therefore, we won't reopen here.
  396. //
  397. pRegContext->hKey = hKeyBase;
  398. else {
  399. if (ERROR_SUCCESS != (dwErr = RegOpenKeyExW(
  400. hKeyBase,
  401. pwszSubKey,
  402. 0, // dwReversed
  403. AccessMask,
  404. &pRegContext->hKey)))
  405. goto ErrorReturn;
  406. pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
  407. }
  408. dwErr = ERROR_SUCCESS;
  409. CommonReturn:
  410. I_MartaRegFree(pwszDupObject);
  411. if (hKeyRemote)
  412. RegCloseKey(hKeyRemote);
  413. *pContext = (MARTA_CONTEXT) pRegContext;
  414. return dwErr;
  415. ErrorReturn:
  416. if (pRegContext) {
  417. MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegContext);
  418. pRegContext = NULL;
  419. }
  420. assert(ERROR_SUCCESS != dwErr);
  421. if (ERROR_SUCCESS == dwErr)
  422. dwErr = ERROR_INTERNAL_ERROR;
  423. goto CommonReturn;
  424. InvalidNameReturn:
  425. dwErr = ERROR_INVALID_NAME;
  426. goto ErrorReturn;
  427. InvalidParameterReturn:
  428. dwErr = ERROR_INVALID_PARAMETER;
  429. goto ErrorReturn;
  430. }
  431. void
  432. I_MartaRegFreeFindData(
  433. IN PREG_FIND_DATA pRegFindData
  434. )
  435. /*++
  436. Routine Description:
  437. Free up the memory associated with the internal structure.
  438. Arguments:
  439. pRegFindData - Internal structure to be freed.
  440. Return Value:
  441. ERROR_SUCCESS in case of success.
  442. ERROR_* otherwise
  443. --*/
  444. {
  445. if (NULL == pRegFindData)
  446. return;
  447. if (pRegFindData->pRegParentContext)
  448. MartaCloseRegistryKeyContext(pRegFindData->pRegParentContext);
  449. I_MartaRegFree(pRegFindData);
  450. }
  451. DWORD
  452. MartaCloseRegistryKeyContext(
  453. IN MARTA_CONTEXT Context
  454. )
  455. /*++
  456. Routine Description:
  457. Close the context.
  458. Arguments:
  459. Context - Context to be closed.
  460. Return Value:
  461. ERROR_SUCCESS in case of success.
  462. ERROR_* otherwise
  463. --*/
  464. {
  465. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  466. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
  467. return ERROR_INVALID_PARAMETER;
  468. //
  469. // If the ref cnt goes to zero then free the handle as well as all other
  470. // associated structures.
  471. //
  472. if (0 == --pRegContext->dwRefCnt) {
  473. if (pRegContext->pRegFindData)
  474. I_MartaRegFreeFindData(pRegContext->pRegFindData);
  475. if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
  476. RegCloseKey(pRegContext->hKey);
  477. I_MartaRegFree(pRegContext->pwszObject);
  478. I_MartaRegFree(pRegContext);
  479. }
  480. return ERROR_SUCCESS;
  481. }
  482. DWORD
  483. MartaAddRefRegistryKeyContext(
  484. IN MARTA_CONTEXT Context
  485. )
  486. /*++
  487. Routine Description:
  488. Bump up the ref count for this context.
  489. Arguments:
  490. Context - Context whose ref count should be bumped up.
  491. Return Value:
  492. ERROR_SUCCESS in case of success.
  493. ERROR_* otherwise
  494. --*/
  495. {
  496. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  497. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
  498. return ERROR_INVALID_PARAMETER;
  499. pRegContext->dwRefCnt++;
  500. return ERROR_SUCCESS;
  501. }
  502. STATIC
  503. inline
  504. BOOL
  505. I_MartaRegIsPredefinedKey(
  506. IN HKEY hKey
  507. )
  508. /*++
  509. Routine Description:
  510. Find if the given key is a predefined key.
  511. Arguments:
  512. key - Handle to the key.
  513. Return Value:
  514. TRUE - if the key is a predefined key.
  515. FALSE - Otherwise.
  516. --*/
  517. {
  518. if (HKEY_CURRENT_USER == hKey ||
  519. HKEY_LOCAL_MACHINE == hKey ||
  520. HKEY_USERS == hKey ||
  521. HKEY_CLASSES_ROOT == hKey ||
  522. HKEY_CURRENT_CONFIG == hKey)
  523. return TRUE;
  524. else
  525. return FALSE;
  526. }
  527. DWORD
  528. MartaOpenRegistryKeyHandleObject(
  529. IN HANDLE Handle,
  530. IN ACCESS_MASK AccessMask,
  531. OUT PMARTA_CONTEXT pContext
  532. )
  533. /*++
  534. Routine Description:
  535. Given a registry key handle, open the context with the desired access mask and
  536. return a context handle.
  537. Arguments:
  538. Handle - Existing registry key handle.
  539. AccessMask - Desired access mask for open.
  540. pContext - To return a handle to the context.
  541. Return Value:
  542. ERROR_SUCCESS in case of success.
  543. ERROR_* otherwise
  544. --*/
  545. {
  546. DWORD dwErr;
  547. HKEY hKey = (HKEY) Handle;
  548. PREG_CONTEXT pRegContext = NULL;
  549. if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegContext)))
  550. goto ErrorReturn;
  551. if (0 == AccessMask || I_MartaRegIsPredefinedKey(hKey))
  552. pRegContext->hKey = hKey;
  553. else {
  554. if (ERROR_SUCCESS != (dwErr = RegOpenKeyExW(
  555. hKey,
  556. NULL, // pwszSubKey
  557. 0, // dwReversed
  558. AccessMask,
  559. &pRegContext->hKey)))
  560. goto ErrorReturn;
  561. pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
  562. }
  563. dwErr = ERROR_SUCCESS;
  564. CommonReturn:
  565. *pContext = (MARTA_CONTEXT) pRegContext;
  566. return dwErr;
  567. ErrorReturn:
  568. if (pRegContext) {
  569. MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegContext);
  570. pRegContext = NULL;
  571. }
  572. assert(ERROR_SUCCESS != dwErr);
  573. if (ERROR_SUCCESS == dwErr)
  574. dwErr = ERROR_INTERNAL_ERROR;
  575. goto CommonReturn;
  576. }
  577. DWORD
  578. MartaGetRegistryKeyParentContext(
  579. IN MARTA_CONTEXT Context,
  580. IN ACCESS_MASK AccessMask,
  581. OUT PMARTA_CONTEXT pParentContext
  582. )
  583. /*++
  584. Routine Description:
  585. Given the context for a registry key, get the context for its parent.
  586. Arguments:
  587. Context - Context for the registry key.
  588. AccessMask - Desired access mask with which the parent will be opened.
  589. pParentContext - To return the context for the parent.
  590. Return Value:
  591. ERROR_SUCCESS in case of success.
  592. ERROR_* otherwise
  593. --*/
  594. {
  595. DWORD dwErr;
  596. LPWSTR pwszParentObject = NULL;
  597. if (ERROR_SUCCESS != (dwErr = MartaConvertRegistryKeyContextToName(
  598. Context, &pwszParentObject)))
  599. goto ErrorReturn;
  600. if (ERROR_SUCCESS != (dwErr = I_MartaRegGetParentString(
  601. pwszParentObject)))
  602. goto NoParentReturn;
  603. MartaOpenRegistryKeyNamedObject(
  604. pwszParentObject,
  605. AccessMask,
  606. pParentContext
  607. );
  608. //
  609. // Ignore any open errors
  610. //
  611. dwErr = ERROR_SUCCESS;
  612. CommonReturn:
  613. I_MartaRegFree(pwszParentObject);
  614. return dwErr;
  615. NoParentReturn:
  616. dwErr = ERROR_SUCCESS;
  617. ErrorReturn:
  618. *pParentContext = NULL;
  619. goto CommonReturn;
  620. }
  621. DWORD
  622. MartaFindFirstRegistryKey(
  623. IN MARTA_CONTEXT Context,
  624. IN ACCESS_MASK AccessMask,
  625. OUT PMARTA_CONTEXT pChildContext
  626. )
  627. /*++
  628. Routine Description:
  629. FInd the first registry key in the given container.
  630. Arguments:
  631. Context - Context for the container.
  632. AccessMask - Desired access mask for opening the child registry key.
  633. pChildContext - To return the context for the first child in the given container.
  634. Return Value:
  635. ERROR_SUCCESS in case of success.
  636. ERROR_* otherwise
  637. Note:
  638. Does not free up the current context.
  639. --*/
  640. {
  641. DWORD dwErr;
  642. PREG_CONTEXT pRegParentContext = (PREG_CONTEXT) Context;
  643. HKEY hKeyParent = pRegParentContext->hKey;
  644. PREG_CONTEXT pRegFirstContext = NULL;
  645. PREG_FIND_DATA pRegFindData; // freed as part of pRegFirstContext
  646. DWORD cSubKeys;
  647. DWORD cchMaxSubKey;
  648. if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegFirstContext)))
  649. goto ErrorReturn;
  650. if (ERROR_SUCCESS != (dwErr = RegQueryInfoKeyW(
  651. hKeyParent,
  652. NULL, // lpszClass
  653. NULL, // lpcchClass
  654. NULL, // lpdwReserved
  655. &cSubKeys,
  656. &cchMaxSubKey,
  657. NULL, // lpcchMaxClass
  658. NULL, // lpcValues
  659. NULL, // lpcchMaxValuesName
  660. NULL, // lpcbMaxValueData
  661. NULL, // lpcbSecurityDescriptor
  662. NULL // lpftLastWriteTime
  663. )))
  664. goto ErrorReturn;
  665. //
  666. // Above returned count doesn't include the terminating null character
  667. //
  668. cchMaxSubKey++;
  669. //
  670. // Note: HKEY_CURRENT_CONFIG returns a cchMaxSubKey of 0 ????
  671. //
  672. if (MAX_PATH > cchMaxSubKey)
  673. cchMaxSubKey = MAX_PATH;
  674. if (NULL == (pRegFindData = (PREG_FIND_DATA) I_MartaRegZeroAlloc(
  675. sizeof(REG_FIND_DATA) + cchMaxSubKey * sizeof(WCHAR))))
  676. goto NotEnoughMemoryReturn;
  677. pRegFirstContext->pRegFindData = pRegFindData;
  678. MartaAddRefRegistryKeyContext((MARTA_CONTEXT) pRegParentContext);
  679. pRegFindData->pRegParentContext = pRegParentContext;
  680. pRegFindData->cSubKeys = cSubKeys;
  681. pRegFindData->cchMaxSubKey = cchMaxSubKey;
  682. pRegFindData->pwszSubKey =
  683. (LPWSTR) (((BYTE *) pRegFindData) + sizeof(REG_FIND_DATA));
  684. //
  685. // Following closes / frees pRegFirstContext
  686. //
  687. dwErr = MartaFindNextRegistryKey(
  688. (MARTA_CONTEXT) pRegFirstContext,
  689. AccessMask,
  690. pChildContext
  691. );
  692. CommonReturn:
  693. return dwErr;
  694. ErrorReturn:
  695. if (pRegFirstContext)
  696. MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegFirstContext);
  697. *pChildContext = NULL;
  698. assert(ERROR_SUCCESS != dwErr);
  699. if (ERROR_SUCCESS == dwErr)
  700. dwErr = ERROR_INTERNAL_ERROR;
  701. goto CommonReturn;
  702. NotEnoughMemoryReturn:
  703. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  704. goto ErrorReturn;
  705. }
  706. DWORD
  707. MartaFindNextRegistryKey(
  708. IN MARTA_CONTEXT Context,
  709. IN ACCESS_MASK AccessMask,
  710. OUT PMARTA_CONTEXT pSiblingContext
  711. )
  712. /*++
  713. Routine Description:
  714. Get the next object in the tree. This is the sibling for the current context.
  715. Arguments:
  716. Context - Context for the current object.
  717. AccessMask - Desired access mask for the opening the sibling.
  718. pSiblingContext - To return a handle for the sibling.
  719. Return Value:
  720. ERROR_SUCCESS in case of success.
  721. ERROR_* otherwise
  722. Note:
  723. Closes the current context.
  724. --*/
  725. {
  726. DWORD dwErr;
  727. PREG_CONTEXT pRegPrevContext = (PREG_CONTEXT) Context;
  728. PREG_CONTEXT pRegSiblingContext = NULL;
  729. //
  730. // Following don't need to be freed or closed
  731. //
  732. PREG_CONTEXT pRegParentContext;
  733. PREG_FIND_DATA pRegFindData;
  734. HKEY hKeyParent;
  735. DWORD cchMaxSubKey;
  736. LPWSTR pwszSubKey;
  737. if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegSiblingContext)))
  738. goto ErrorReturn;
  739. //
  740. // Move the FindData on to the sibling context
  741. //
  742. pRegFindData = pRegPrevContext->pRegFindData;
  743. if (NULL == pRegFindData)
  744. goto InvalidParameterReturn;
  745. pRegPrevContext->pRegFindData = NULL;
  746. pRegSiblingContext->pRegFindData = pRegFindData;
  747. if (pRegFindData->iSubKey >= pRegFindData->cSubKeys)
  748. goto NoMoreItemsReturn;
  749. pRegParentContext = pRegFindData->pRegParentContext;
  750. hKeyParent = pRegParentContext->hKey;
  751. pwszSubKey = pRegFindData->pwszSubKey;
  752. cchMaxSubKey = pRegFindData->cchMaxSubKey;
  753. if (ERROR_SUCCESS != (dwErr = RegEnumKeyExW(
  754. hKeyParent,
  755. pRegFindData->iSubKey,
  756. pwszSubKey,
  757. &cchMaxSubKey,
  758. NULL, // lpdwReserved
  759. NULL, // lpszClass
  760. NULL, // lpcchClass
  761. NULL // lpftLastWriteTime
  762. )))
  763. goto ErrorReturn;
  764. pRegFindData->iSubKey++;
  765. if (pRegParentContext->pwszObject)
  766. //
  767. // Ignore errors. Mainly here for testing purposes.
  768. //
  769. I_MartaRegCreateChildString(
  770. pRegParentContext->pwszObject,
  771. pwszSubKey,
  772. &pRegSiblingContext->pwszObject
  773. );
  774. if (ERROR_SUCCESS == (dwErr = RegOpenKeyExW(
  775. hKeyParent,
  776. pwszSubKey,
  777. 0, // dwReversed
  778. AccessMask,
  779. &pRegSiblingContext->hKey)))
  780. pRegSiblingContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
  781. //
  782. // For an error still return this context. This allows the caller
  783. // to continue on to the next sibling object and know there was an
  784. // error with this sibling object
  785. //
  786. CommonReturn:
  787. MartaCloseRegistryKeyContext(Context);
  788. *pSiblingContext = (MARTA_CONTEXT) pRegSiblingContext;
  789. return dwErr;
  790. ErrorReturn:
  791. if (pRegSiblingContext) {
  792. MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegSiblingContext);
  793. pRegSiblingContext = NULL;
  794. }
  795. // kedar wants this mapped to success
  796. if (ERROR_NO_MORE_ITEMS == dwErr)
  797. dwErr = ERROR_SUCCESS;
  798. goto CommonReturn;
  799. InvalidParameterReturn:
  800. dwErr = ERROR_INVALID_PARAMETER;
  801. goto ErrorReturn;
  802. NoMoreItemsReturn:
  803. dwErr = ERROR_NO_MORE_ITEMS;
  804. goto ErrorReturn;
  805. }
  806. DWORD
  807. MartaConvertRegistryKeyContextToName(
  808. IN MARTA_CONTEXT Context,
  809. OUT LPWSTR *ppwszObject
  810. )
  811. /*++
  812. Routine Description:
  813. Returns the NT Object Name for the given context. Allocates memory.
  814. Arguments:
  815. Context - Context for the registry key.
  816. ppwszObject - To return the name of the registry key.
  817. Return Value:
  818. ERROR_SUCCESS in case of success.
  819. ERROR_* otherwise
  820. --*/
  821. {
  822. DWORD dwErr = ERROR_SUCCESS;
  823. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  824. LPWSTR pwszObject = NULL;
  825. BYTE Buff[512];
  826. ULONG cLen = 0;
  827. POBJECT_NAME_INFORMATION pNI; // not allocated
  828. POBJECT_NAME_INFORMATION pAllocNI = NULL;
  829. NTSTATUS Status;
  830. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
  831. goto InvalidParameterReturn;
  832. if (pRegContext->pwszObject) {
  833. //
  834. // Already have the object's name
  835. //
  836. if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(
  837. pRegContext->pwszObject, &pwszObject)))
  838. goto ErrorReturn;
  839. else
  840. goto SuccessReturn;
  841. } else {
  842. HKEY hKey = pRegContext->hKey;
  843. LPWSTR pwszPath;
  844. DWORD cchPath;
  845. //
  846. // First, determine the size of the buffer we need...
  847. //
  848. pNI = (POBJECT_NAME_INFORMATION) Buff;
  849. Status = NtQueryObject(hKey,
  850. ObjectNameInformation,
  851. pNI,
  852. sizeof(Buff),
  853. &cLen);
  854. if (!NT_SUCCESS(Status) || sizeof(*pNI) > cLen ||
  855. 0 == pNI->Name.Length) {
  856. if (Status == STATUS_BUFFER_TOO_SMALL ||
  857. Status == STATUS_INFO_LENGTH_MISMATCH ||
  858. Status == STATUS_BUFFER_OVERFLOW) {
  859. //
  860. // Allocate a big enough buffer
  861. //
  862. if (NULL == (pAllocNI = (POBJECT_NAME_INFORMATION)
  863. I_MartaRegNonzeroAlloc(cLen)))
  864. goto NotEnoughMemoryReturn;
  865. pNI = pAllocNI;
  866. Status = NtQueryObject(hKey,
  867. ObjectNameInformation,
  868. pNI,
  869. cLen,
  870. NULL);
  871. if (!NT_SUCCESS(Status))
  872. goto StatusErrorReturn;
  873. } else {
  874. //
  875. // Check if one of the predefined base keys
  876. //
  877. LPCWSTR pwszBaseKey = NULL;
  878. if (HKEY_LOCAL_MACHINE == hKey)
  879. pwszBaseKey = L"MACHINE";
  880. else if (HKEY_USERS == hKey)
  881. pwszBaseKey = L"USERS";
  882. else if (HKEY_CLASSES_ROOT == hKey)
  883. pwszBaseKey = L"CLASSES_ROOT";
  884. else if (HKEY_CURRENT_USER == hKey)
  885. pwszBaseKey = L"CURRENT_USER";
  886. else if (HKEY_CURRENT_CONFIG == hKey)
  887. pwszBaseKey = L"CONFIG";
  888. else if (!NT_SUCCESS(Status))
  889. goto StatusErrorReturn;
  890. else
  891. goto InvalidHandleReturn;
  892. if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(
  893. pwszBaseKey, &pwszObject)))
  894. goto ErrorReturn;
  895. else
  896. goto SuccessReturn;
  897. }
  898. }
  899. pwszPath = pNI->Name.Buffer;
  900. cchPath = pNI->Name.Length / sizeof(WCHAR);
  901. if (REG_OBJ_TAG_LEN > cchPath ||
  902. 0 != _wcsnicmp(pwszPath, REG_OBJ_TAG, REG_OBJ_TAG_LEN))
  903. goto BadPathnameReturn;
  904. pwszPath += REG_OBJ_TAG_LEN;
  905. cchPath -= REG_OBJ_TAG_LEN;
  906. if (NULL == (pwszObject = (LPWSTR) I_MartaRegNonzeroAlloc(
  907. (cchPath + 1) * sizeof(WCHAR))))
  908. goto NotEnoughMemoryReturn;
  909. memcpy(pwszObject, pwszPath, cchPath * sizeof(WCHAR));
  910. pwszObject[cchPath] = L'\0';
  911. }
  912. SuccessReturn:
  913. dwErr = ERROR_SUCCESS;
  914. CommonReturn:
  915. I_MartaRegFree(pAllocNI);
  916. *ppwszObject = pwszObject;
  917. return dwErr;
  918. StatusErrorReturn:
  919. dwErr = RtlNtStatusToDosError(Status);
  920. ErrorReturn:
  921. assert(NULL == pwszObject);
  922. assert(ERROR_SUCCESS != dwErr);
  923. if (ERROR_SUCCESS == dwErr)
  924. dwErr = ERROR_INTERNAL_ERROR;
  925. goto CommonReturn;
  926. NotEnoughMemoryReturn:
  927. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  928. goto ErrorReturn;
  929. InvalidHandleReturn:
  930. dwErr = ERROR_INVALID_HANDLE;
  931. goto ErrorReturn;
  932. BadPathnameReturn:
  933. dwErr = ERROR_BAD_PATHNAME;
  934. goto ErrorReturn;
  935. InvalidParameterReturn:
  936. dwErr = ERROR_INVALID_PARAMETER;
  937. goto ErrorReturn;
  938. }
  939. DWORD
  940. MartaConvertRegistryKeyContextToHandle(
  941. IN MARTA_CONTEXT Context,
  942. OUT HANDLE *pHandle
  943. )
  944. /*++
  945. Routine Description:
  946. The following is for testing
  947. The returned Handle isn't duplicated. It has the same lifetime as
  948. the Context
  949. Arguments:
  950. Context - Context whose properties the caller has asked for.
  951. pHandle - To return the handle.
  952. Return Value:
  953. ERROR_SUCCESS in case of success.
  954. ERROR_NOT_ENOUGH_MEMORY if allocation failed.
  955. --*/
  956. {
  957. DWORD dwErr;
  958. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  959. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt) {
  960. *pHandle = NULL;
  961. dwErr = ERROR_INVALID_PARAMETER;
  962. } else {
  963. *pHandle = (HANDLE) pRegContext->hKey;
  964. dwErr = ERROR_SUCCESS;
  965. }
  966. return dwErr;
  967. }
  968. DWORD
  969. MartaGetRegistryKeyProperties(
  970. IN MARTA_CONTEXT Context,
  971. IN OUT PMARTA_OBJECT_PROPERTIES pProperties
  972. )
  973. /*++
  974. Routine Description:
  975. Return the properties for registry key represented by the context.
  976. Arguments:
  977. Context - Context whose properties the caller has asked for.
  978. pProperties - To return the properties for this registry key.
  979. Return Value:
  980. ERROR_SUCCESS in case of success.
  981. ERROR_* otherwise
  982. --*/
  983. {
  984. pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
  985. return ERROR_SUCCESS;
  986. }
  987. DWORD
  988. MartaGetRegistryKeyTypeProperties(
  989. IN OUT PMARTA_OBJECT_TYPE_PROPERTIES pProperties
  990. )
  991. /*++
  992. Routine Description:
  993. Return the properties of registry key objects.
  994. Arguments:
  995. pProperties - To return the properties of registry key objects.
  996. Return Value:
  997. ERROR_SUCCESS.
  998. --*/
  999. {
  1000. const GENERIC_MAPPING GenMap = {
  1001. KEY_READ,
  1002. KEY_WRITE,
  1003. KEY_EXECUTE,
  1004. KEY_ALL_ACCESS
  1005. };
  1006. pProperties->dwFlags |= MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG;
  1007. pProperties->dwFlags |= MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG;
  1008. pProperties->GenMap = GenMap;
  1009. return ERROR_SUCCESS;
  1010. }
  1011. DWORD
  1012. MartaGetRegistryKeyRights(
  1013. IN MARTA_CONTEXT Context,
  1014. IN SECURITY_INFORMATION SecurityInfo,
  1015. OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Get the security descriptor for the given handle.
  1020. Arguments:
  1021. Context - Context for registry key.
  1022. SecurityInfo - Type of security information to be read.
  1023. ppSecurityDescriptor - To return a self-relative security decriptor pointer.
  1024. Return Value:
  1025. ERROR_SUCCESS in case of success.
  1026. ERROR_* otherwise
  1027. --*/
  1028. {
  1029. DWORD dwErr = ERROR_SUCCESS;
  1030. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  1031. DWORD cbSize;
  1032. PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1033. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
  1034. goto InvalidParameterReturn;
  1035. //
  1036. // First, get the size we need
  1037. //
  1038. cbSize = 0;
  1039. dwErr = RegGetKeySecurity(
  1040. pRegContext->hKey,
  1041. SecurityInfo,
  1042. NULL, // pSecDesc
  1043. &cbSize
  1044. );
  1045. if (ERROR_INSUFFICIENT_BUFFER == dwErr) {
  1046. if (NULL == (pSecurityDescriptor =
  1047. (PISECURITY_DESCRIPTOR) I_MartaRegNonzeroAlloc(cbSize)))
  1048. goto NotEnoughMemoryReturn;
  1049. dwErr = RegGetKeySecurity(
  1050. pRegContext->hKey,
  1051. SecurityInfo,
  1052. pSecurityDescriptor,
  1053. &cbSize
  1054. );
  1055. } else if (ERROR_SUCCESS == dwErr)
  1056. dwErr = ERROR_INTERNAL_ERROR;
  1057. if (ERROR_SUCCESS != dwErr)
  1058. goto ErrorReturn;
  1059. CommonReturn:
  1060. *ppSecurityDescriptor = pSecurityDescriptor;
  1061. return dwErr;
  1062. ErrorReturn:
  1063. if (pSecurityDescriptor) {
  1064. I_MartaRegFree(pSecurityDescriptor);
  1065. pSecurityDescriptor = NULL;
  1066. }
  1067. assert(ERROR_SUCCESS != dwErr);
  1068. if (ERROR_SUCCESS == dwErr)
  1069. dwErr = ERROR_INTERNAL_ERROR;
  1070. goto CommonReturn;
  1071. NotEnoughMemoryReturn:
  1072. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1073. goto ErrorReturn;
  1074. InvalidParameterReturn:
  1075. dwErr = ERROR_INVALID_PARAMETER;
  1076. goto ErrorReturn;
  1077. }
  1078. DWORD
  1079. MartaSetRegistryKeyRights(
  1080. IN MARTA_CONTEXT Context,
  1081. IN SECURITY_INFORMATION SecurityInfo,
  1082. IN PSECURITY_DESCRIPTOR pSecurityDescriptor
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. Set the given security descriptor on the registry key represented by the context.
  1087. Arguments:
  1088. Context - Context for the registry key.
  1089. SecurityInfo - Type of security info to be stamped on the registry key.
  1090. pSecurityDescriptor - Security descriptor to be stamped.
  1091. Return Value:
  1092. ERROR_SUCCESS in case of success.
  1093. ERROR_* otherwise
  1094. --*/
  1095. {
  1096. DWORD dwErr = ERROR_SUCCESS;
  1097. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  1098. if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
  1099. goto InvalidParameterReturn;
  1100. dwErr = RegSetKeySecurity(
  1101. pRegContext->hKey,
  1102. SecurityInfo,
  1103. pSecurityDescriptor
  1104. );
  1105. CommonReturn:
  1106. return dwErr;
  1107. InvalidParameterReturn:
  1108. dwErr = ERROR_INVALID_PARAMETER;
  1109. goto CommonReturn;
  1110. }
  1111. ACCESS_MASK
  1112. MartaGetRegistryKeyDesiredAccess(
  1113. IN SECURITY_OPEN_TYPE OpenType,
  1114. IN BOOL Attribs,
  1115. IN SECURITY_INFORMATION SecurityInfo
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. Gets the access required to open object to be able to set or get the
  1120. specified security info.
  1121. Arguments:
  1122. OpenType - Flag indicating if the object is to be opened to read or write
  1123. the security information
  1124. Attribs - TRUE indicates that additional access bits should be returned.
  1125. SecurityInfo - owner/group/dacl/sacl
  1126. Return Value:
  1127. Desired access mask with which open should be called.
  1128. --*/
  1129. {
  1130. ACCESS_MASK DesiredAccess = 0;
  1131. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  1132. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  1133. {
  1134. switch (OpenType)
  1135. {
  1136. case READ_ACCESS_RIGHTS:
  1137. DesiredAccess |= READ_CONTROL;
  1138. break;
  1139. case WRITE_ACCESS_RIGHTS:
  1140. DesiredAccess |= WRITE_OWNER;
  1141. break;
  1142. case MODIFY_ACCESS_RIGHTS:
  1143. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  1144. break;
  1145. }
  1146. }
  1147. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  1148. {
  1149. switch (OpenType)
  1150. {
  1151. case READ_ACCESS_RIGHTS:
  1152. DesiredAccess |= READ_CONTROL;
  1153. break;
  1154. case WRITE_ACCESS_RIGHTS:
  1155. DesiredAccess |= WRITE_DAC;
  1156. break;
  1157. case MODIFY_ACCESS_RIGHTS:
  1158. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  1159. break;
  1160. }
  1161. }
  1162. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  1163. {
  1164. DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
  1165. }
  1166. if (TRUE == Attribs)
  1167. {
  1168. DesiredAccess |= KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
  1169. }
  1170. return (DesiredAccess);
  1171. }
  1172. ACCESS_MASK
  1173. MartaGetRegistryKey32DesiredAccess(
  1174. IN SECURITY_OPEN_TYPE OpenType,
  1175. IN BOOL Attribs,
  1176. IN SECURITY_INFORMATION SecurityInfo
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Gets the access required to open object to be able to set or get the
  1181. specified security info.
  1182. Arguments:
  1183. OpenType - Flag indicating if the object is to be opened to read or write
  1184. the security information
  1185. Attribs - TRUE indicates that additional access bits should be returned.
  1186. SecurityInfo - owner/group/dacl/sacl
  1187. Return Value:
  1188. Desired access mask with which open should be called.
  1189. --*/
  1190. {
  1191. ACCESS_MASK DesiredAccess = KEY_WOW64_32KEY;
  1192. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  1193. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  1194. {
  1195. switch (OpenType)
  1196. {
  1197. case READ_ACCESS_RIGHTS:
  1198. DesiredAccess |= READ_CONTROL;
  1199. break;
  1200. case WRITE_ACCESS_RIGHTS:
  1201. DesiredAccess |= WRITE_OWNER;
  1202. break;
  1203. case MODIFY_ACCESS_RIGHTS:
  1204. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  1205. break;
  1206. }
  1207. }
  1208. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  1209. {
  1210. switch (OpenType)
  1211. {
  1212. case READ_ACCESS_RIGHTS:
  1213. DesiredAccess |= READ_CONTROL;
  1214. break;
  1215. case WRITE_ACCESS_RIGHTS:
  1216. DesiredAccess |= WRITE_DAC;
  1217. break;
  1218. case MODIFY_ACCESS_RIGHTS:
  1219. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  1220. break;
  1221. }
  1222. }
  1223. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  1224. {
  1225. DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
  1226. }
  1227. if (TRUE == Attribs)
  1228. {
  1229. DesiredAccess |= KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
  1230. }
  1231. return (DesiredAccess);
  1232. }
  1233. ACCESS_MASK
  1234. MartaGetDefaultDesiredAccess(
  1235. IN SECURITY_OPEN_TYPE OpenType,
  1236. IN BOOL Attribs,
  1237. IN SECURITY_INFORMATION SecurityInfo
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. Gets the access required to open object to be able to set or get the
  1242. specified security info. This default routine is used for all resource
  1243. managers except for files/reg.
  1244. Arguments:
  1245. OpenType - Flag indicating if the object is to be opened to read or write
  1246. the security information
  1247. Attribs - TRUE indicates that additional access bits should be returned.
  1248. SecurityInfo - owner/group/dacl/sacl
  1249. Return Value:
  1250. Desired access mask with which open should be called.
  1251. --*/
  1252. {
  1253. ACCESS_MASK DesiredAccess = 0;
  1254. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  1255. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  1256. {
  1257. switch (OpenType)
  1258. {
  1259. case READ_ACCESS_RIGHTS:
  1260. DesiredAccess |= READ_CONTROL;
  1261. break;
  1262. case WRITE_ACCESS_RIGHTS:
  1263. DesiredAccess |= WRITE_OWNER;
  1264. break;
  1265. case MODIFY_ACCESS_RIGHTS:
  1266. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  1267. break;
  1268. }
  1269. }
  1270. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  1271. {
  1272. switch (OpenType)
  1273. {
  1274. case READ_ACCESS_RIGHTS:
  1275. DesiredAccess |= READ_CONTROL;
  1276. break;
  1277. case WRITE_ACCESS_RIGHTS:
  1278. DesiredAccess |= WRITE_DAC;
  1279. break;
  1280. case MODIFY_ACCESS_RIGHTS:
  1281. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  1282. break;
  1283. }
  1284. }
  1285. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  1286. {
  1287. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  1288. }
  1289. return (DesiredAccess);
  1290. }
  1291. DWORD
  1292. MartaReopenRegistryKeyContext(
  1293. IN OUT MARTA_CONTEXT Context,
  1294. IN ACCESS_MASK AccessMask
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Given the context for a registry key, close the existing handle if one exists
  1299. and reopen the context with new permissions.
  1300. Arguments:
  1301. Context - Context to be reopened.
  1302. AccessMask - Permissions for the reopen.
  1303. Return Value:
  1304. ERROR_SUCCESS in case of success.
  1305. ERROR_* otherwise
  1306. --*/
  1307. {
  1308. DWORD dwErr;
  1309. HKEY hKey;
  1310. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  1311. PREG_FIND_DATA pRegFindData = pRegContext->pRegFindData;
  1312. PREG_CONTEXT pRegParentContext = pRegFindData->pRegParentContext;
  1313. dwErr = RegOpenKeyExW(
  1314. pRegParentContext->hKey,
  1315. pRegFindData->pwszSubKey,
  1316. 0, // dwReversed
  1317. AccessMask,
  1318. &hKey);
  1319. if (ERROR_SUCCESS == dwErr) {
  1320. if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
  1321. RegCloseKey(pRegContext->hKey);
  1322. pRegContext->hKey = hKey;
  1323. pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
  1324. }
  1325. return dwErr;
  1326. }
  1327. DWORD
  1328. MartaReopenRegistryKeyOrigContext(
  1329. IN OUT MARTA_CONTEXT Context,
  1330. IN ACCESS_MASK AccessMask
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. Reopen the original context with a new access mask. Close the original
  1335. handle.
  1336. Arguments:
  1337. Context - Context to reopen.
  1338. AccessMask - Desired access for open.
  1339. Return Value:
  1340. ERROR_SUCCESS in case of success.
  1341. ERROR_NOT_ENOUGH_MEMORY if allocation failed.
  1342. --*/
  1343. {
  1344. DWORD dwErr;
  1345. HKEY hKey;
  1346. PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
  1347. dwErr = RegOpenKeyExW(
  1348. pRegContext->hKey,
  1349. NULL, // pwszSubKey
  1350. 0, // dwReversed
  1351. AccessMask,
  1352. &hKey);
  1353. if (ERROR_SUCCESS == dwErr) {
  1354. if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
  1355. RegCloseKey(pRegContext->hKey);
  1356. pRegContext->hKey = hKey;
  1357. pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
  1358. }
  1359. return dwErr;
  1360. }
  1361. DWORD
  1362. MartaGetRegistryKeyNameFromContext(
  1363. IN MARTA_CONTEXT Context,
  1364. OUT LPWSTR *pObjectName
  1365. )
  1366. /*++
  1367. Routine Description:
  1368. Get the name of the registry key from the context. This routine allocates
  1369. memory required to hold the name of the object.
  1370. Arguments:
  1371. Context - Handle to the context.
  1372. pObjectName - To return the pointer to the allocated string.
  1373. Return Value:
  1374. ERROR_SUCCESS in case of success.
  1375. ERROR_* otherwise
  1376. --*/
  1377. {
  1378. return MartaConvertRegistryKeyContextToName(
  1379. Context,
  1380. pObjectName
  1381. );
  1382. }
  1383. DWORD
  1384. MartaGetRegistryKeyParentName(
  1385. IN LPWSTR ObjectName,
  1386. OUT LPWSTR *pParentName
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. Given the name of a registry key return the name of its parent. The routine
  1391. allocates memory required to hold the parent name.
  1392. Arguments:
  1393. ObjectName - Name of the registry key.
  1394. pParentName - To return the pointer to the allocated parent name.
  1395. In case of the root of the tree, we return NULL parent with ERROR_SUCCESS.
  1396. Return Value:
  1397. ERROR_SUCCESS in case of success.
  1398. ERROR_* otherwise
  1399. --*/
  1400. {
  1401. ULONG Length = wcslen(ObjectName) + 1;
  1402. PWCHAR Name = (PWCHAR) I_MartaRegNonzeroAlloc(sizeof(WCHAR) * Length);
  1403. DWORD dwErr = ERROR_SUCCESS;
  1404. *pParentName = NULL;
  1405. if (!Name)
  1406. {
  1407. return ERROR_NOT_ENOUGH_MEMORY;
  1408. }
  1409. wcscpy((WCHAR *) Name, ObjectName);
  1410. dwErr = I_MartaRegGetParentString(Name);
  1411. if (ERROR_SUCCESS != dwErr)
  1412. {
  1413. I_MartaRegFree(Name);
  1414. if (ERROR_INVALID_NAME == dwErr)
  1415. return ERROR_SUCCESS;
  1416. return dwErr;
  1417. }
  1418. *pParentName = Name;
  1419. return dwErr;
  1420. }