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.

1871 lines
69 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 1994.
  5. //
  6. // File: registry.cxx
  7. //
  8. // Contents: local functions
  9. //
  10. // History: 8/94 davemont Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #include <alsup.hxx>
  16. #include <martaevt.h>
  17. //
  18. // Registry generic mapping
  19. //
  20. GENERIC_MAPPING gRegGenMapping = {STANDARD_RIGHTS_READ | 0x1,
  21. STANDARD_RIGHTS_WRITE | 0x2,
  22. STANDARD_RIGHTS_EXECUTE | 0x4,
  23. STANDARD_RIGHTS_REQUIRED | 0x3F};
  24. //+---------------------------------------------------------------------------
  25. //
  26. // Function : GetDesiredAccess
  27. //
  28. // Synopsis : Gets the access required to open object to be able to set or
  29. // get the specified security info.
  30. //
  31. // Arguments: IN [SecurityOpenType] - Flag indicating if the object is to be
  32. // opened to read or write the DACL
  33. //
  34. //----------------------------------------------------------------------------
  35. ACCESS_MASK RegGetDesiredAccess(IN SECURITY_OPEN_TYPE OpenType,
  36. IN SECURITY_INFORMATION SecurityInfo)
  37. {
  38. acDebugOut((DEB_TRACE_ACC, "in GetDesiredAccess \n"));
  39. ACCESS_MASK DesiredAccess = 0;
  40. if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  41. (SecurityInfo & GROUP_SECURITY_INFORMATION) )
  42. {
  43. switch (OpenType)
  44. {
  45. case READ_ACCESS_RIGHTS:
  46. DesiredAccess |= READ_CONTROL;
  47. break;
  48. case WRITE_ACCESS_RIGHTS:
  49. DesiredAccess |= WRITE_OWNER;
  50. break;
  51. case MODIFY_ACCESS_RIGHTS:
  52. DesiredAccess |= READ_CONTROL | WRITE_OWNER;
  53. break;
  54. }
  55. }
  56. if (SecurityInfo & DACL_SECURITY_INFORMATION)
  57. {
  58. switch (OpenType)
  59. {
  60. case READ_ACCESS_RIGHTS:
  61. DesiredAccess |= READ_CONTROL;
  62. break;
  63. case WRITE_ACCESS_RIGHTS:
  64. DesiredAccess |= WRITE_DAC;
  65. break;
  66. case MODIFY_ACCESS_RIGHTS:
  67. DesiredAccess |= READ_CONTROL | WRITE_DAC;
  68. break;
  69. }
  70. }
  71. if (SecurityInfo & SACL_SECURITY_INFORMATION)
  72. {
  73. DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
  74. }
  75. acDebugOut((DEB_TRACE_ACC, "out RegGetDesiredAccess: %lu\n", DesiredAccess));
  76. return (DesiredAccess);
  77. }
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Function: OpenRegistryObject
  81. //
  82. // Synopsis: Opens the specified registry object
  83. //
  84. // Arguments: [IN pwszRegistry] -- The name of the registry key
  85. // to open
  86. // [IN AccessMask] -- Flags indicating if the object
  87. // is to be opened to read or write
  88. // the DACL
  89. // [OUT pHandle] -- Where the open handle is
  90. // returned
  91. //
  92. // Returns: ERROR_SUCCESS -- Success
  93. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  94. // ERROR_INVALID_PARAMETER -- A bad name was given
  95. //
  96. //----------------------------------------------------------------------------
  97. DWORD
  98. OpenRegistryObject(IN LPWSTR pwszRegistry,
  99. IN ACCESS_MASK AccessMask,
  100. OUT PHANDLE pHandle)
  101. {
  102. acDebugOut((DEB_TRACE, "in OpenRegistryObject\n"));
  103. DWORD dwErr;
  104. HKEY hBase;
  105. if(pwszRegistry != NULL)
  106. {
  107. WCHAR wszName[MAX_PATH + 1];
  108. PWSTR pwszName;
  109. //
  110. // save the object since we must crack it to go to remote machines
  111. //
  112. dwErr = AccGetBufferOfSizeW(pwszRegistry,
  113. wszName,
  114. &pwszName);
  115. if(dwErr == ERROR_SUCCESS)
  116. {
  117. PWSTR pwszRemaining, pwszMachine;
  118. //
  119. // Separate the names
  120. //
  121. dwErr = ParseName(pwszName,
  122. &pwszMachine,
  123. &pwszRemaining);
  124. if(dwErr == ERROR_SUCCESS)
  125. {
  126. PWSTR pwszKey = NULL;
  127. //
  128. // look for the key names localization required.
  129. //
  130. if (pwszRemaining != NULL)
  131. {
  132. PWSTR pwszBase = pwszRemaining;
  133. pwszKey = wcschr(pwszRemaining, L'\\');
  134. if(pwszKey != NULL)
  135. {
  136. *pwszKey = L'\0';
  137. pwszKey++;
  138. }
  139. //
  140. // Now, figure out what our base key will be
  141. //
  142. if(_wcsicmp(pwszBase, L"MACHINE") == 0)
  143. {
  144. hBase = HKEY_LOCAL_MACHINE;
  145. }
  146. else if(_wcsicmp(pwszBase, L"USERS") == 0 ||
  147. _wcsicmp(pwszBase, L"USER") == 0 )
  148. {
  149. hBase = HKEY_USERS;
  150. }
  151. //
  152. // The next three are valid only for the local machine
  153. //
  154. else if(pwszMachine == NULL &&
  155. _wcsicmp(pwszBase, L"CLASSES_ROOT") == 0)
  156. {
  157. hBase = HKEY_CLASSES_ROOT;
  158. }
  159. else if(pwszMachine == NULL &&
  160. _wcsicmp(pwszBase,L"CURRENT_USER") == 0)
  161. {
  162. hBase = HKEY_CURRENT_USER;
  163. }
  164. else if(pwszMachine == NULL &&
  165. _wcsicmp(pwszBase, L"CONFIG") == 0)
  166. {
  167. hBase = HKEY_CURRENT_CONFIG;
  168. }
  169. else
  170. {
  171. dwErr = ERROR_INVALID_PARAMETER;
  172. }
  173. }
  174. else
  175. {
  176. dwErr = ERROR_INVALID_PARAMETER;
  177. }
  178. if(dwErr == ERROR_SUCCESS)
  179. {
  180. //
  181. // if it is a remote name, connect to that registry
  182. //
  183. if(pwszMachine != NULL)
  184. {
  185. HKEY hMach = hBase;
  186. dwErr = RegConnectRegistry(pwszMachine,
  187. hMach,
  188. &hBase);
  189. }
  190. //
  191. // Now, open the key
  192. //
  193. if(dwErr == ERROR_SUCCESS)
  194. {
  195. dwErr = RegOpenKeyEx(hBase,
  196. pwszKey,
  197. 0,
  198. AccessMask,
  199. (PHKEY)pHandle);
  200. if(pwszMachine != NULL)
  201. {
  202. RegCloseKey(hBase);
  203. }
  204. }
  205. }
  206. }
  207. AccFreeBufferOfSizeW(wszName, pwszName);
  208. }
  209. }
  210. else
  211. {
  212. dwErr = ERROR_INVALID_PARAMETER;
  213. }
  214. acDebugOut((DEB_TRACE, "Out OpenRegistryObject: %lu\n", dwErr));
  215. return(dwErr);
  216. }
  217. //+---------------------------------------------------------------------------
  218. //
  219. // Function: ReadRegistryPropertyRights
  220. //
  221. // Synopsis: Gets the specified security info for the specified registry
  222. // object
  223. //
  224. // Arguments: [IN pwszRegistry] -- The reg key to get the rights
  225. // for
  226. // [IN pRightsList] -- SecurityInfo to read based
  227. // on properties
  228. // [IN cRights] -- Number of items in rights list
  229. // [IN AccessList] -- Access List to fill in
  230. //
  231. // Returns: ERROR_SUCCESS -- Success
  232. // ERROR_INVALID_PARAMETER -- A bad property was encountered
  233. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  234. //
  235. //----------------------------------------------------------------------------
  236. DWORD
  237. ReadRegistryPropertyRights(IN LPWSTR pwszRegistry,
  238. IN PACTRL_RIGHTS_INFO pRightsList,
  239. IN ULONG cRights,
  240. IN CAccessList& AccessList)
  241. {
  242. acDebugOut((DEB_TRACE, "in ReadRegistryPropertyRights\n"));
  243. HANDLE hReg;
  244. DWORD dwErr;
  245. //
  246. // Currently, there are only registry object properties
  247. //
  248. ASSERT(cRights == 1 && pRightsList[0].pwszProperty == NULL);
  249. if(cRights != 1 || pRightsList[0].pwszProperty != NULL)
  250. {
  251. return(ERROR_INVALID_PARAMETER);
  252. }
  253. //
  254. // Set the lookup server name
  255. //
  256. dwErr = SetAccessListLookupServer( pwszRegistry,
  257. AccessList );
  258. //
  259. // Open the registry key
  260. //
  261. if(dwErr == ERROR_SUCCESS)
  262. {
  263. dwErr = OpenRegistryObject(pwszRegistry,
  264. RegGetDesiredAccess(READ_ACCESS_RIGHTS,
  265. pRightsList[0].SeInfo),
  266. &hReg);
  267. }
  268. if(dwErr == ERROR_SUCCESS)
  269. {
  270. PSECURITY_DESCRIPTOR pSD;
  271. dwErr = ReadRegistrySecurityInfo(hReg,
  272. pRightsList[0].SeInfo,
  273. &pSD);
  274. //
  275. // If that worked, we'll have to get the parent SD, if it exists,
  276. // and see if we can determine the inheritance on our current object
  277. //
  278. if(dwErr == ERROR_SUCCESS)
  279. {
  280. if((pRightsList[0].SeInfo & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) != 0 &&
  281. !FLAG_ON(((PISECURITY_DESCRIPTOR)pSD)->Control,
  282. SE_SACL_AUTO_INHERITED |
  283. SE_DACL_AUTO_INHERITED))
  284. {
  285. //
  286. // Ok, it's downlevel, so get the parent SD...
  287. //
  288. PSECURITY_DESCRIPTOR pParentSD;
  289. dwErr = GetRegistryParentRights(pwszRegistry,
  290. pRightsList[0].SeInfo,
  291. &pParentSD);
  292. //
  293. // Also, the routine to convert from nt4 to nt5 security
  294. // descriptor requires that we have the owner and group,
  295. // so we may have to reread the child SD if we don't have
  296. // that info
  297. //
  298. if(dwErr == ERROR_SUCCESS && (!FLAG_ON(pRightsList[0].SeInfo,
  299. OWNER_SECURITY_INFORMATION) ||
  300. !FLAG_ON(pRightsList[0].SeInfo,
  301. GROUP_SECURITY_INFORMATION)))
  302. {
  303. AccFree(pSD);
  304. pSD = NULL;
  305. dwErr = ReadRegistrySecurityInfo(hReg,
  306. pRightsList[0].SeInfo |
  307. OWNER_SECURITY_INFORMATION |
  308. GROUP_SECURITY_INFORMATION,
  309. &pSD);
  310. }
  311. //
  312. // A NULL parent SD means this object has no parent!
  313. //
  314. if(dwErr == ERROR_SUCCESS && pParentSD != NULL)
  315. {
  316. PSECURITY_DESCRIPTOR pNewSD;
  317. dwErr = ConvertToAutoInheritSD(pParentSD,
  318. pSD,
  319. TRUE,
  320. &gRegGenMapping,
  321. &pNewSD);
  322. if(dwErr == ERROR_SUCCESS)
  323. {
  324. dwErr = AccessList.AddSD(pNewSD,
  325. pRightsList[0].SeInfo,
  326. pRightsList[0].pwszProperty);
  327. DestroyPrivateObjectSecurity(&pNewSD);
  328. }
  329. AccFree(pParentSD);
  330. }
  331. }
  332. else
  333. {
  334. //
  335. // Simply add the SD to our list
  336. //
  337. dwErr = AccessList.AddSD(pSD,
  338. pRightsList[0].SeInfo,
  339. pRightsList[0].pwszProperty);
  340. }
  341. //
  342. // Make sure to free the security descriptor...
  343. //
  344. AccFree(pSD);
  345. }
  346. RegCloseKey((HKEY)hReg);
  347. }
  348. acDebugOut((DEB_TRACE, "Out ReadRegistryPropertyRights: %lu\n", dwErr));
  349. return(dwErr);
  350. }
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Function: ReadRegistryRights
  354. //
  355. // Synopsis: Gets the specified security info for the specified registry
  356. // object
  357. //
  358. // Arguments: [IN hRegistry] -- Reg handle to get the rights
  359. // for
  360. // [IN pRightsList] -- SecurityInfo to read based
  361. // on properties
  362. // [IN cRights] -- Number of items in rights list
  363. // [IN AccessList] -- Access List to fill in
  364. //
  365. // Returns: ERROR_SUCCESS -- Success
  366. // ERROR_INVALID_PARAMETER -- A bad property was encountered
  367. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  368. //
  369. //----------------------------------------------------------------------------
  370. DWORD
  371. ReadRegistryRights(IN HANDLE hRegistry,
  372. IN PACTRL_RIGHTS_INFO pRightsList,
  373. IN ULONG cRights,
  374. IN CAccessList& AccessList)
  375. {
  376. acDebugOut((DEB_TRACE, "in ReadRegistryRights\n"));
  377. DWORD dwErr;
  378. //
  379. // Currently, there are only registry object properties
  380. //
  381. ASSERT(cRights == 1 && pRightsList[0].pwszProperty == NULL);
  382. if(cRights != 1 || pRightsList[0].pwszProperty != NULL)
  383. {
  384. return(ERROR_INVALID_PARAMETER);
  385. }
  386. PSECURITY_DESCRIPTOR pSD = NULL;
  387. dwErr = ReadRegistrySecurityInfo(hRegistry,
  388. pRightsList[0].SeInfo,
  389. &pSD);
  390. if((dwErr != ERROR_SUCCESS) || (pSD == NULL))
  391. {
  392. return(dwErr);
  393. }
  394. //
  395. // Take a look at it... If it's a downlevel object, let's reread it as an uplevel, if
  396. // possible
  397. //
  398. if(!FLAG_ON(((PISECURITY_DESCRIPTOR)pSD)->Control,
  399. SE_SACL_AUTO_INHERITED |
  400. SE_DACL_AUTO_INHERITED))
  401. {
  402. PWSTR pwszRegPath = NULL;
  403. dwErr = ConvertRegHandleToName((HKEY)hRegistry,
  404. &pwszRegPath);
  405. if(dwErr != ERROR_SUCCESS)
  406. {
  407. if(dwErr == ERROR_INVALID_HANDLE)
  408. {
  409. //
  410. // It's remote, so add it as is...
  411. //
  412. dwErr = AccessList.AddSD(pSD,
  413. pRightsList->SeInfo,
  414. pRightsList->pwszProperty);
  415. }
  416. }
  417. else
  418. {
  419. dwErr = ReadRegistryPropertyRights(pwszRegPath,
  420. pRightsList,
  421. cRights,
  422. AccessList);
  423. AccFree(pwszRegPath);
  424. }
  425. }
  426. else
  427. {
  428. //
  429. // It's already uplevel, so add it as is...
  430. //
  431. dwErr = AccessList.AddSD(pSD,
  432. pRightsList->SeInfo,
  433. pRightsList->pwszProperty);
  434. }
  435. AccFree(pSD);
  436. acDebugOut((DEB_TRACE, "Out ReadRegistryRights: %lu\n", dwErr));
  437. return(dwErr);
  438. }
  439. //+---------------------------------------------------------------------------
  440. //
  441. // Function: ReadRegistrySecurityInfo
  442. //
  443. // Synopsis: Reads the specified security info for the handle's registry
  444. // key object
  445. //
  446. // Arguments: [IN hRegistry] -- The handle to the object to
  447. // get the rights for
  448. // [IN SeInfo] -- SecurityInfo to read based
  449. // [OUT ppOwner] -- The owner sid
  450. // [OUT ppGroup] -- The group sid
  451. // [OUT pDAcl] -- The DACL
  452. // [OUT pSAcl] -- The SACL
  453. // [OUT pSD] -- The security descriptor itself
  454. //
  455. // Returns: ERROR_SUCCESS -- Success
  456. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  457. //
  458. //----------------------------------------------------------------------------
  459. DWORD
  460. ReadRegistrySecurityInfo(IN HANDLE hRegistry,
  461. IN SECURITY_INFORMATION SeInfo,
  462. OUT PSECURITY_DESCRIPTOR *ppSD)
  463. {
  464. acDebugOut((DEB_TRACE, "in ReadRegistrySecurityInfo \n"));
  465. ULONG cSize = 0;
  466. DWORD dwErr;
  467. //
  468. // First, get the size we need
  469. //
  470. dwErr = RegGetKeySecurity((HKEY)hRegistry,
  471. SeInfo,
  472. *ppSD,
  473. &cSize);
  474. if(dwErr == ERROR_INSUFFICIENT_BUFFER)
  475. {
  476. dwErr = ERROR_SUCCESS;
  477. *ppSD = (PISECURITY_DESCRIPTOR)AccAlloc(cSize);
  478. if(*ppSD == NULL)
  479. {
  480. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  481. }
  482. else
  483. {
  484. dwErr = RegGetKeySecurity((HKEY)hRegistry,
  485. SeInfo,
  486. *ppSD,
  487. &cSize);
  488. if(dwErr == ERROR_SUCCESS &&
  489. FLAG_ON(((SECURITY_DESCRIPTOR *)*ppSD)->Control,SE_SELF_RELATIVE))
  490. {
  491. PSECURITY_DESCRIPTOR pAbs;
  492. dwErr = MakeSDAbsolute(*ppSD,
  493. SeInfo,
  494. &pAbs);
  495. if(dwErr == ERROR_SUCCESS)
  496. {
  497. AccFree(*ppSD);
  498. *ppSD = pAbs;
  499. }
  500. }
  501. }
  502. }
  503. else
  504. {
  505. ASSERT(dwErr != ERROR_INSUFFICIENT_BUFFER);
  506. }
  507. acDebugOut((DEB_TRACE, "Out ReadRegistrySecurityInfo: %lu\n", dwErr));
  508. return(dwErr);
  509. }
  510. //+---------------------------------------------------------------------------
  511. //
  512. // Function: GetRegistryParentRights
  513. //
  514. // Synopsis: Determines who the parent is, and gets the access rights
  515. // for it. It is used to aid in determining what the approriate
  516. // inheritance bits are.
  517. //
  518. // This operation does not make sense for kernel objects
  519. //
  520. // Arguments: [IN pwszRegistry] -- The reg path to get the parent
  521. // for
  522. // [IN SeInfo] -- The security information to do
  523. // the read for
  524. // [OUT ppDAcl] -- Where the DACL is returned
  525. // [OUT ppSAcl] -- Where the SACL is returned
  526. // [OUT ppSD] -- Where the Security Descriptor
  527. // is returned
  528. //
  529. // Returns: ERROR_SUCCESS -- Success
  530. //
  531. //
  532. //----------------------------------------------------------------------------
  533. DWORD
  534. GetRegistryParentRights(IN LPWSTR pwszRegistry,
  535. IN SECURITY_INFORMATION SeInfo,
  536. OUT PSECURITY_DESCRIPTOR *ppSD)
  537. {
  538. DWORD dwErr = ERROR_SUCCESS;
  539. //
  540. // Basically, we'll figure out who our parent is, and get their info
  541. //
  542. PWSTR pwszLastComp = wcsrchr(pwszRegistry, L'\\');
  543. if(pwszLastComp == NULL)
  544. {
  545. //
  546. // Ok, we must be at the root, so we won't have any inheritance
  547. //
  548. //
  549. // Return success after nulling out SD.
  550. //
  551. *ppSD = NULL;
  552. }
  553. else
  554. {
  555. //
  556. // We'll shorten our path, and then get the info
  557. //
  558. *pwszLastComp = L'\0';
  559. HANDLE hReg;
  560. //
  561. // Don't want owner or group
  562. //
  563. SeInfo &= ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
  564. dwErr = OpenRegistryObject(pwszRegistry,
  565. RegGetDesiredAccess(READ_ACCESS_RIGHTS,SeInfo),
  566. &hReg);
  567. if(dwErr == ERROR_SUCCESS)
  568. {
  569. dwErr = ReadRegistrySecurityInfo(hReg,
  570. SeInfo,
  571. ppSD);
  572. RegCloseKey((HKEY)hReg);
  573. }
  574. *pwszLastComp = L'\\';
  575. }
  576. return(dwErr);
  577. }
  578. //+---------------------------------------------------------------------------
  579. //
  580. // Function: SetRegistrySecurityInfo
  581. //
  582. // Synopsis: Sets the specified security info on the specified registry
  583. // object
  584. //
  585. // Arguments: [IN hService] -- The handle of the object
  586. // [IN SeInfo] -- Flag indicating what security
  587. // info to set
  588. // [IN pwszProperty] -- The property on the object to
  589. // set
  590. // For kernel objects, this MBZ
  591. // [IN pSD] -- The security descriptor to set
  592. //
  593. // Returns: ERROR_SUCCESS -- Success
  594. // ERROR_INVALID_PARAMETER -- A bad property was given
  595. //
  596. //----------------------------------------------------------------------------
  597. DWORD
  598. SetRegistrySecurityInfo(IN HANDLE hRegistry,
  599. IN SECURITY_INFORMATION SeInfo,
  600. IN PWSTR pwszProperty,
  601. IN PSECURITY_DESCRIPTOR pSD)
  602. {
  603. acDebugOut((DEB_TRACE, "in SetNamedRegistrySecurityInfo\n"));
  604. DWORD dwErr;
  605. //
  606. // Registry keys don't have properties
  607. //
  608. if(pwszProperty != NULL)
  609. {
  610. dwErr = ERROR_INVALID_PARAMETER;
  611. }
  612. else
  613. {
  614. //
  615. // Marta only writes uplevel security descriptors.
  616. //
  617. // The caller of SetRegistrySecurityInfo will call with SE_xACL_AUTO_INHERITED off in those
  618. // cases that it wants the underlying registry to do auto inheritance.
  619. // The caller of SetRegistrySecurityInfo will call with SE_xACL_AUTO_INHERITED on in those
  620. // cases that it wants the underlying registry to simply store the bits.
  621. //
  622. // In the later case, the OS uses the SE_xACL_AUTO_INHERIT_REQ bit as a flag indicating
  623. // that it is OK to preserve SE_xACL_AUTO_INHERITED bit.
  624. //
  625. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION)) {
  626. ((PISECURITY_DESCRIPTOR)pSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
  627. }
  628. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION)) {
  629. ((PISECURITY_DESCRIPTOR)pSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
  630. }
  631. dwErr = RegSetKeySecurity((HKEY)hRegistry,
  632. SeInfo,
  633. pSD);
  634. }
  635. acDebugOut((DEB_TRACE, "Out SetRegistrySecurityInfo: %lu\n", dwErr));
  636. return(dwErr);
  637. }
  638. #define CLEANUP_ON_INTERRUPT(pstopflag) \
  639. if(*pstopflag != 0) \
  640. { \
  641. goto RegCleanup; \
  642. }
  643. //+---------------------------------------------------------------------------
  644. //
  645. // Function: SetAndPropagateRegistryPropertyRights
  646. //
  647. // Synopsis: Sets the access on the given registry path and propagates
  648. // it as necessary
  649. //
  650. // Arguments: [IN pwszRegistry] -- The path to set and propagate
  651. // [IN pwszProperty] -- The registry property to
  652. // operate upon
  653. // [IN RootAccList] -- The CAccessList class that has
  654. // the security descriptor/info
  655. // [IN pfStopFlag] -- Address of the stop flag
  656. // to be monitored
  657. // [IN pcProcessed] -- count of processed items to
  658. // be incremented.
  659. //
  660. // Returns: ERROR_SUCCESS -- Success
  661. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  662. //
  663. //----------------------------------------------------------------------------
  664. DWORD
  665. SetAndPropagateRegistryPropertyRights(IN PWSTR pwszRegistry,
  666. IN PWSTR pwszProperty,
  667. IN CAccessList& RootAccList,
  668. IN PULONG pfStopFlag,
  669. IN PULONG pcProcessed)
  670. {
  671. acDebugOut((DEB_TRACE, "in SetAndPropagateRegistryPropertyRights\n"));
  672. DWORD dwErr = ERROR_SUCCESS;
  673. //
  674. // First, get our security descriptor and sec info
  675. //
  676. HKEY hReg = NULL;
  677. PSECURITY_DESCRIPTOR pSD = NULL;
  678. PSECURITY_DESCRIPTOR pParentSD = NULL;
  679. SECURITY_INFORMATION SeInfo = 0;
  680. dwErr = RootAccList.BuildSDForAccessList(&pSD,
  681. &SeInfo,
  682. ACCLIST_SD_ABSOK);
  683. if(dwErr == ERROR_SUCCESS)
  684. {
  685. //
  686. // Next, open the registry
  687. //
  688. dwErr = OpenRegistryObject(pwszRegistry,
  689. RegGetDesiredAccess(MODIFY_ACCESS_RIGHTS,
  690. SeInfo) |
  691. KEY_ENUMERATE_SUB_KEYS |
  692. KEY_QUERY_VALUE,
  693. (PHANDLE)&hReg);
  694. if(dwErr == ERROR_SUCCESS)
  695. {
  696. //
  697. // Next, get our parent security descriptor
  698. //
  699. //
  700. // If we are only setting the owner or group, we don't need to get the parent
  701. //
  702. if (FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) ||
  703. FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) ) {
  704. dwErr = GetRegistryParentRights(pwszRegistry,
  705. SeInfo,
  706. &pParentSD);
  707. }
  708. if(dwErr == ERROR_SUCCESS)
  709. {
  710. //
  711. // Make the call
  712. //
  713. dwErr = SetAndPropRegRights(hReg,
  714. pwszRegistry,
  715. SeInfo,
  716. pParentSD,
  717. pSD,
  718. pfStopFlag,
  719. pcProcessed);
  720. }
  721. }
  722. }
  723. //
  724. // Clean up
  725. //
  726. if(hReg != NULL)
  727. {
  728. RegCloseKey(hReg);
  729. }
  730. AccFree(pParentSD);
  731. acDebugOut((DEB_TRACE,
  732. "Out SetAndPropagateRegistryPropertyRights: %ld\n", dwErr));
  733. return(dwErr);
  734. }
  735. //+---------------------------------------------------------------------------
  736. //
  737. // Function: SetAndPropagateRegistryPropertyRightsByHandle
  738. //
  739. // Synopsis: Same as above, but assumes the registry key has already
  740. // been opened
  741. //
  742. // Arguments: [IN hReg] -- The registry key to use
  743. // [IN RootAccList] -- The CAccessList class that has
  744. // the security descriptor/info
  745. // [IN pfStopFlag] -- Address of the stop flag
  746. // to be monitored
  747. // [IN pcProcessed] -- count of processed items to
  748. // be incremented.
  749. //
  750. // Returns: ERROR_SUCCESS -- Success
  751. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  752. //
  753. //----------------------------------------------------------------------------
  754. DWORD
  755. SetAndPropagateRegistryPropertyRightsByHandle(IN HKEY hReg,
  756. IN CAccessList& RootAccList,
  757. IN PULONG pfStopFlag,
  758. IN PULONG pcProcessed)
  759. {
  760. acDebugOut((DEB_TRACE, "in SetAndPropagateRegistryPropertyRightsByHandle\n"));
  761. DWORD dwErr = ERROR_SUCCESS;
  762. PSECURITY_DESCRIPTOR pParentSD = NULL;
  763. HANDLE hObject = NULL;
  764. BOOL fUplevelAcl = TRUE;
  765. PWSTR pwszRegPath = NULL;
  766. //
  767. // First, get our security descriptor and sec info
  768. //
  769. PSECURITY_DESCRIPTOR pSD = NULL;
  770. SECURITY_INFORMATION SeInfo = 0;
  771. dwErr = RootAccList.BuildSDForAccessList(&pSD,
  772. &SeInfo,
  773. ACCLIST_SD_ABSOK);
  774. if(dwErr == ERROR_SUCCESS)
  775. {
  776. //
  777. // If we are only setting the owner or group, we don't need to get the parent
  778. //
  779. if (FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) ||
  780. FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) ) {
  781. dwErr = ConvertRegHandleToName(hReg,
  782. &pwszRegPath);
  783. if((dwErr != ERROR_SUCCESS) || (pwszRegPath == NULL))
  784. {
  785. if(dwErr == ERROR_INVALID_HANDLE)
  786. {
  787. dwErr = ERROR_SUCCESS;
  788. }
  789. }
  790. else
  791. {
  792. dwErr = GetRegistryParentRights(pwszRegPath,
  793. SeInfo,
  794. &pParentSD);
  795. }
  796. }
  797. if(dwErr == ERROR_SUCCESS)
  798. {
  799. //
  800. // Make the call
  801. //
  802. dwErr = SetAndPropRegRights(hReg,
  803. NULL,
  804. SeInfo,
  805. pParentSD,
  806. pSD,
  807. pfStopFlag,
  808. pcProcessed);
  809. if(dwErr == ERROR_ACCESS_DENIED)
  810. {
  811. //
  812. // See if we can reopen the path adding in readcontrol, and try it all again
  813. //
  814. if(pwszRegPath == NULL)
  815. {
  816. dwErr = ConvertRegHandleToName(hReg,
  817. &pwszRegPath);
  818. }
  819. if(pwszRegPath != NULL)
  820. {
  821. dwErr = SetAndPropagateRegistryPropertyRights(pwszRegPath,
  822. NULL,
  823. RootAccList,
  824. pfStopFlag,
  825. pcProcessed);
  826. }
  827. }
  828. }
  829. }
  830. //
  831. // Clean up
  832. //
  833. AccFree(pwszRegPath);
  834. AccFree(pParentSD);
  835. acDebugOut((DEB_TRACE,
  836. "Out SetAndPropagateRegistryPropertyRightsByHandle: %ld\n", dwErr));
  837. return(dwErr);
  838. }
  839. //+---------------------------------------------------------------------------
  840. //
  841. // Function: PropagateRegRightsDeep, recursive
  842. //
  843. // Synopsis: Does a deep propagation of the access. At the same time, it
  844. // will update NT4 acls to NT5 acls. This function is only
  845. // called on downlevel registries, so the update will always
  846. // happen (where appropriate). The algorithm is:
  847. // - Read the current security descriptor from the object
  848. // - If it's a downlevel acl, update it using the OLD
  849. // parent security descriptor (to set any inheritied aces)
  850. // - Update the security descriptor using the NEW parent
  851. // security descriptor.
  852. // - Repeat for its children. (This is necessar, since there
  853. // could have been unmarked inheritance off of the old
  854. // security descriptor)
  855. //
  856. // Arguments: [IN pOldParentSD] -- The previous parent SD (before
  857. // the current parent SD was
  858. // stamped on the object)
  859. // [IN pParentSD] -- The current parent sd
  860. // [IN SeInfo] -- What is being written
  861. // [IN hParent] -- Opened parent registry key
  862. // [IN pcProcessed] -- Where the number processed is
  863. // returned.
  864. // [IN pfStopFlag] -- Stop flag to monitor
  865. // [IN fProtectedFlag] -- Determines whether the acls are already
  866. // protected
  867. // [IN hProcessToken] -- Handle to the process token
  868. // [IN LogList] -- List of keys to which propagation failed
  869. //
  870. // Returns: ERROR_SUCCESS -- Success
  871. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  872. //
  873. //----------------------------------------------------------------------------
  874. DWORD
  875. PropagateRegRightsDeep(IN PSECURITY_DESCRIPTOR pOldParentSD,
  876. IN PSECURITY_DESCRIPTOR pParentSD,
  877. IN SECURITY_INFORMATION SeInfo,
  878. IN HKEY hParent,
  879. IN PULONG pcProcessed,
  880. IN PULONG pfStopFlag,
  881. IN ULONG fProtectedFlag,
  882. IN HANDLE hProcessToken,
  883. IN OUT CSList& LogList)
  884. {
  885. acDebugOut((DEB_TRACE, "in PropagteRegRightsDeep\n"));
  886. DWORD dwErr = ERROR_SUCCESS;
  887. SECURITY_DESCRIPTOR *pChildSD = NULL;
  888. PSECURITY_DESCRIPTOR pNewSD = NULL;
  889. BOOL fUpdateChild = FALSE; // Write out the child?
  890. BOOL fAccFreeChild = TRUE; // How to free the child
  891. //
  892. // Check to see if we've reached full protection saturation
  893. //
  894. if(fProtectedFlag == (SE_DACL_PROTECTED | SE_SACL_PROTECTED))
  895. {
  896. acDebugOut((DEB_TRACE_PROP, "Parent is fully or effectively protected\n"));
  897. return(ERROR_SUCCESS);
  898. }
  899. HKEY hChild = NULL;
  900. ULONG cSubKeys;
  901. dwErr = RegQueryInfoKey(hParent,
  902. NULL,
  903. NULL,
  904. NULL,
  905. &cSubKeys,
  906. NULL,
  907. NULL,
  908. NULL,
  909. NULL,
  910. NULL,
  911. NULL,
  912. NULL);
  913. CLEANUP_ON_INTERRUPT(pfStopFlag);
  914. if(dwErr == ERROR_SUCCESS && cSubKeys != 0)
  915. {
  916. WCHAR wszBuff[MAX_PATH + 1];
  917. ULONG iIndex = 0;
  918. ULONG cSize;
  919. FILETIME WriteTime;
  920. while(dwErr == ERROR_SUCCESS)
  921. {
  922. cSize = MAX_PATH + 1;
  923. dwErr = RegEnumKeyEx(hParent,
  924. iIndex,
  925. wszBuff,
  926. &cSize,
  927. NULL,
  928. NULL,
  929. NULL,
  930. &WriteTime);
  931. if(dwErr == ERROR_NO_MORE_ITEMS)
  932. {
  933. dwErr = ERROR_SUCCESS;
  934. break;
  935. }
  936. acDebugOut((DEB_TRACE_PROP,"Propagating to %ws\n", wszBuff));
  937. CLEANUP_ON_INTERRUPT(pfStopFlag);
  938. //
  939. // Now, determine if we need to propagate or not...
  940. //
  941. if(dwErr == ERROR_SUCCESS)
  942. {
  943. ULONG cSDLen = 0;
  944. BOOL fWriteSD = FALSE;
  945. dwErr = RegOpenKeyEx(hParent,
  946. wszBuff,
  947. 0,
  948. RegGetDesiredAccess(MODIFY_ACCESS_RIGHTS,
  949. SeInfo) |
  950. KEY_ENUMERATE_SUB_KEYS |
  951. KEY_QUERY_VALUE,
  952. &hChild);
  953. if(dwErr == ERROR_SUCCESS)
  954. {
  955. //
  956. // Get our number of children
  957. //
  958. dwErr = RegQueryInfoKey(hChild,
  959. NULL,
  960. NULL,
  961. NULL,
  962. &cSubKeys,
  963. NULL,
  964. NULL,
  965. NULL,
  966. NULL,
  967. NULL,
  968. NULL,
  969. NULL);
  970. if ( dwErr == ERROR_INSUFFICIENT_BUFFER ) {
  971. acDebugOut((DEB_ERROR,"RegQueryInfoKey failure on %ws\n", wszBuff));
  972. }
  973. if(dwErr == ERROR_SUCCESS)
  974. {
  975. CLEANUP_ON_INTERRUPT(pfStopFlag);
  976. //
  977. // Read the current security descriptor
  978. //
  979. dwErr = ReadRegistrySecurityInfo(hChild,
  980. SeInfo,
  981. (PSECURITY_DESCRIPTOR *)&pChildSD);
  982. CLEANUP_ON_INTERRUPT(pfStopFlag);
  983. if(dwErr == ERROR_SUCCESS &&
  984. !(FLAG_ON(pChildSD->Control,
  985. SE_DACL_AUTO_INHERITED |
  986. SE_SACL_AUTO_INHERITED)))
  987. {
  988. //
  989. // Before we convert this, we may need to reread the SD... if
  990. // we don't have owner and group
  991. //
  992. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) ||
  993. !FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  994. {
  995. AccFree(pChildSD);
  996. pChildSD = NULL;
  997. dwErr = ReadRegistrySecurityInfo(
  998. hChild,
  999. SeInfo |
  1000. OWNER_SECURITY_INFORMATION |
  1001. GROUP_SECURITY_INFORMATION,
  1002. (PSECURITY_DESCRIPTOR *)&pChildSD);
  1003. if(dwErr == ERROR_ACCESS_DENIED)
  1004. {
  1005. RegCloseKey(hChild);
  1006. dwErr = RegOpenKeyEx(hParent,
  1007. wszBuff,
  1008. 0,
  1009. RegGetDesiredAccess(MODIFY_ACCESS_RIGHTS,
  1010. SeInfo |
  1011. OWNER_SECURITY_INFORMATION |
  1012. GROUP_SECURITY_INFORMATION) |
  1013. KEY_ENUMERATE_SUB_KEYS |
  1014. KEY_QUERY_VALUE,
  1015. &hChild);
  1016. if(dwErr == ERROR_SUCCESS)
  1017. {
  1018. dwErr = ReadRegistrySecurityInfo(
  1019. hChild,
  1020. SeInfo |
  1021. OWNER_SECURITY_INFORMATION |
  1022. GROUP_SECURITY_INFORMATION,
  1023. (PSECURITY_DESCRIPTOR *)&pChildSD);
  1024. }
  1025. }
  1026. }
  1027. if(dwErr == ERROR_SUCCESS)
  1028. {
  1029. dwErr = ConvertToAutoInheritSD(pOldParentSD,
  1030. pChildSD,
  1031. TRUE,
  1032. &gRegGenMapping,
  1033. &pNewSD);
  1034. AccFree(pChildSD);
  1035. if(dwErr == ERROR_SUCCESS)
  1036. {
  1037. pChildSD = (SECURITY_DESCRIPTOR *)pNewSD;
  1038. fAccFreeChild = FALSE;
  1039. pNewSD = NULL;
  1040. }
  1041. }
  1042. }
  1043. //
  1044. // Now, compute the new security descriptor
  1045. if(dwErr == ERROR_SUCCESS)
  1046. {
  1047. DebugDumpSD("CPOS ParentSD", pParentSD);
  1048. DebugDumpSD("CPOS CreatorSD", pChildSD);
  1049. if(CreatePrivateObjectSecurityEx(pParentSD,
  1050. pChildSD,
  1051. &pNewSD,
  1052. NULL,
  1053. TRUE,
  1054. SEF_DACL_AUTO_INHERIT |
  1055. SEF_SACL_AUTO_INHERIT |
  1056. SEF_AVOID_OWNER_CHECK |
  1057. SEF_AVOID_PRIVILEGE_CHECK,
  1058. hProcessToken,
  1059. &gRegGenMapping) == FALSE)
  1060. {
  1061. dwErr = GetLastError();
  1062. }
  1063. }
  1064. #ifdef DBG
  1065. else
  1066. {
  1067. DebugDumpSD("CPOS NewChild", pNewSD);
  1068. }
  1069. #endif
  1070. if(dwErr == ERROR_SUCCESS)
  1071. {
  1072. //
  1073. // If the resultant child is protected, don't bother propagating
  1074. // down.
  1075. //
  1076. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
  1077. {
  1078. if(DACL_PROTECTED(pNewSD))
  1079. {
  1080. fProtectedFlag |= SE_DACL_PROTECTED;
  1081. }
  1082. }
  1083. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
  1084. {
  1085. if(SACL_PROTECTED(pNewSD))
  1086. {
  1087. fProtectedFlag |= SE_SACL_PROTECTED;
  1088. }
  1089. }
  1090. if(FLAG_ON( fProtectedFlag, (SE_DACL_PROTECTED | SE_SACL_PROTECTED)))
  1091. {
  1092. cSubKeys = 0;
  1093. dwErr = InsertPropagationFailureEntry(LogList,
  1094. 0,
  1095. fProtectedFlag,
  1096. wszBuff);
  1097. }
  1098. //
  1099. // If we haven't changed the acl, security descriptor, then
  1100. // we can also quit
  1101. //
  1102. if(EqualSecurityDescriptors(pNewSD, pChildSD))
  1103. {
  1104. cSubKeys = 0;
  1105. }
  1106. }
  1107. }
  1108. //
  1109. // Now, if it's a directory, call ourselves
  1110. //
  1111. if(dwErr == ERROR_SUCCESS && cSubKeys != 0)
  1112. {
  1113. dwErr = PropagateRegRightsDeep(pChildSD,
  1114. pNewSD,
  1115. SeInfo,
  1116. hChild,
  1117. pcProcessed,
  1118. pfStopFlag,
  1119. fProtectedFlag,
  1120. hProcessToken,
  1121. LogList);
  1122. if(dwErr == ERROR_ACCESS_DENIED)
  1123. {
  1124. dwErr = InsertPropagationFailureEntry(LogList,
  1125. dwErr,
  1126. 0,
  1127. wszBuff);
  1128. }
  1129. }
  1130. //
  1131. // Free the old child, since we won't need it anymore
  1132. //
  1133. if(fAccFreeChild == TRUE)
  1134. {
  1135. AccFree(pChildSD);
  1136. }
  1137. else
  1138. {
  1139. DestroyPrivateObjectSecurity((PSECURITY_DESCRIPTOR *)
  1140. &pChildSD);
  1141. }
  1142. pChildSD = NULL;
  1143. }
  1144. }
  1145. acDebugOut((DEB_TRACE_PROP,
  1146. "Processed %ws: %lu\n",
  1147. wszBuff,
  1148. dwErr));
  1149. //
  1150. // Finally, set the new security
  1151. //
  1152. if(dwErr == ERROR_SUCCESS)
  1153. {
  1154. //
  1155. // Now, we'll simply stamp it on the object
  1156. //
  1157. dwErr = SetRegistrySecurityInfo(hChild,
  1158. SeInfo,
  1159. NULL,
  1160. pNewSD);
  1161. (*pcProcessed)++;
  1162. }
  1163. DestroyPrivateObjectSecurity(&pNewSD);
  1164. pNewSD = NULL;
  1165. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1166. iIndex++;
  1167. }
  1168. }
  1169. if(dwErr == ERROR_NO_MORE_FILES)
  1170. {
  1171. dwErr = ERROR_SUCCESS;
  1172. }
  1173. RegCleanup:
  1174. if(hChild != NULL)
  1175. {
  1176. RegCloseKey(hChild);
  1177. }
  1178. if(pNewSD != NULL)
  1179. {
  1180. DestroyPrivateObjectSecurity(&pNewSD);
  1181. }
  1182. acDebugOut((DEB_TRACE,
  1183. "Out PropagteRegRightsDeep: %ld\n", dwErr));
  1184. return(dwErr);
  1185. }
  1186. //+---------------------------------------------------------------------------
  1187. //
  1188. // Function: SetAndPropRegRights
  1189. //
  1190. // Synopsis: Sets the access on the given registry path and propagates
  1191. // it as necessary
  1192. //
  1193. // Arguments: [IN hReg] -- Handle to the reg. object to set
  1194. // [IN pwszPath] -- Registry path referred to by hReg,
  1195. // if known
  1196. // [IN SeInfo] -- Security information to set
  1197. // [IN pParentSD] -- Security descriptor of the parent
  1198. // [IN pSD] -- SD to set
  1199. // [IN pfStopFlag] -- Address of the stop flag
  1200. // to be monitored
  1201. // [IN pcProcessed] -- count of processed items to
  1202. // be incremented.
  1203. //
  1204. // Returns: ERROR_SUCCESS -- Success
  1205. //
  1206. //----------------------------------------------------------------------------
  1207. DWORD
  1208. SetAndPropRegRights(IN HKEY hReg,
  1209. IN PWSTR pwszPath,
  1210. IN SECURITY_INFORMATION SeInfo,
  1211. IN PSECURITY_DESCRIPTOR pParentSD,
  1212. IN PSECURITY_DESCRIPTOR pSD,
  1213. IN PULONG pfStopFlag,
  1214. IN PULONG pcProcessed)
  1215. {
  1216. acDebugOut((DEB_TRACE, "in SetAndPropRegRights\n"));
  1217. DWORD dwErr = ERROR_SUCCESS;
  1218. PSECURITY_DESCRIPTOR pOldObjSD = NULL;
  1219. PSECURITY_DESCRIPTOR pUpdatedSD = NULL;
  1220. PSECURITY_DESCRIPTOR pVerifySD = NULL;
  1221. BOOL fManualProp = FALSE;
  1222. ULONG fProtected = 0;
  1223. ULONG cSubKeys;
  1224. HANDLE hProcessToken = NULL;
  1225. PSID pOwner = NULL, pGroup = NULL;
  1226. CSList FailureLogList(FreePropagationFailureListEntry);
  1227. //
  1228. // Ok, read the existing security
  1229. //
  1230. dwErr = ReadRegistrySecurityInfo(hReg,
  1231. SeInfo,
  1232. &pOldObjSD);
  1233. //
  1234. // Now, we'll write out the current, and then read it back and make sure
  1235. // that it's properly updated
  1236. //
  1237. if(dwErr == ERROR_SUCCESS &&
  1238. FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION) )
  1239. {
  1240. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1241. dwErr = SetRegistrySecurityInfo(hReg,
  1242. SeInfo,
  1243. NULL,
  1244. pSD);
  1245. if(dwErr == ERROR_SUCCESS)
  1246. {
  1247. (*pcProcessed)++;
  1248. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1249. dwErr = ReadRegistrySecurityInfo(hReg,
  1250. SeInfo,
  1251. &pVerifySD);
  1252. if(dwErr == ERROR_SUCCESS)
  1253. {
  1254. //
  1255. // Check to see if this was done uplevel...
  1256. //
  1257. PISECURITY_DESCRIPTOR pISD = (PISECURITY_DESCRIPTOR)pVerifySD;
  1258. if(!(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) &&
  1259. FLAG_ON(pISD->Control, SE_DACL_AUTO_INHERITED)) &&
  1260. !(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) &&
  1261. FLAG_ON(pISD->Control, SE_SACL_AUTO_INHERITED)))
  1262. {
  1263. //
  1264. // It's not uplevel, so we'll turn the AutoInherit
  1265. // flags on, rewrite it, and do our own propagation,
  1266. // only if this is a container and we're setting the
  1267. // dacl or sacl
  1268. //
  1269. if(FLAG_ON(SeInfo,
  1270. (DACL_SECURITY_INFORMATION |
  1271. SACL_SECURITY_INFORMATION)))
  1272. {
  1273. fManualProp = TRUE;
  1274. }
  1275. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
  1276. {
  1277. pISD->Control |= SE_DACL_AUTO_INHERITED;
  1278. }
  1279. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
  1280. {
  1281. pISD->Control |= SE_SACL_AUTO_INHERITED;
  1282. }
  1283. //
  1284. // Go ahead and upgrade it to autoinherit
  1285. //
  1286. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) ||
  1287. !FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  1288. {
  1289. //
  1290. // Need to reread it to get the owner and group
  1291. //
  1292. AccFree(pVerifySD);
  1293. dwErr = ReadRegistrySecurityInfo(hReg,
  1294. SeInfo |
  1295. OWNER_SECURITY_INFORMATION |
  1296. GROUP_SECURITY_INFORMATION,
  1297. &pVerifySD);
  1298. //
  1299. // If we failed to read it because we didn't originally have permissions
  1300. // and we have the path, we'll try to reopen the handle with the
  1301. // proper rights
  1302. //
  1303. if(dwErr == ERROR_ACCESS_DENIED && pwszPath != NULL)
  1304. {
  1305. HKEY hReg2;
  1306. dwErr = OpenRegistryObject(pwszPath,
  1307. RegGetDesiredAccess(READ_ACCESS_RIGHTS,
  1308. SeInfo |
  1309. OWNER_SECURITY_INFORMATION |
  1310. GROUP_SECURITY_INFORMATION),
  1311. (PHANDLE)&hReg2);
  1312. if(dwErr == ERROR_SUCCESS)
  1313. {
  1314. dwErr = ReadRegistrySecurityInfo(hReg2,
  1315. SeInfo |
  1316. OWNER_SECURITY_INFORMATION |
  1317. GROUP_SECURITY_INFORMATION,
  1318. &pVerifySD);
  1319. RegCloseKey(hReg2);
  1320. }
  1321. }
  1322. //
  1323. // Set our owner/group in the old security descriptor
  1324. //
  1325. if(dwErr == ERROR_SUCCESS)
  1326. {
  1327. BOOL fDefaulted;
  1328. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION))
  1329. {
  1330. if(!GetSecurityDescriptorOwner(pVerifySD, &pOwner, &fDefaulted))
  1331. {
  1332. dwErr = GetLastError();
  1333. }
  1334. }
  1335. if(!FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  1336. {
  1337. if(!GetSecurityDescriptorGroup(pVerifySD, &pGroup, &fDefaulted))
  1338. {
  1339. dwErr = GetLastError();
  1340. }
  1341. }
  1342. if(dwErr == ERROR_SUCCESS)
  1343. {
  1344. //
  1345. // If it's self relative, we'll have to make it absolute.
  1346. //
  1347. if(FLAG_ON(((SECURITY_DESCRIPTOR *)pSD)->Control,
  1348. SE_SELF_RELATIVE))
  1349. {
  1350. PSECURITY_DESCRIPTOR pSD2;
  1351. dwErr = MakeSDAbsolute(pSD,
  1352. SeInfo,
  1353. &pSD2,
  1354. pOwner,
  1355. pGroup);
  1356. if(dwErr == ERROR_SUCCESS)
  1357. {
  1358. AccFree(pSD);
  1359. pSD = pSD2;
  1360. }
  1361. }
  1362. else
  1363. {
  1364. if(pOwner != NULL)
  1365. {
  1366. if(SetSecurityDescriptorOwner(pOldObjSD,
  1367. pOwner,
  1368. FALSE) == FALSE)
  1369. {
  1370. dwErr = GetLastError();
  1371. }
  1372. }
  1373. if(pGroup != NULL)
  1374. {
  1375. if(SetSecurityDescriptorGroup(pOldObjSD,
  1376. pGroup,
  1377. FALSE) == FALSE)
  1378. {
  1379. dwErr = GetLastError();
  1380. }
  1381. }
  1382. }
  1383. }
  1384. }
  1385. }
  1386. if(dwErr == ERROR_SUCCESS)
  1387. {
  1388. dwErr = GetCurrentToken( &hProcessToken );
  1389. }
  1390. if(dwErr == ERROR_SUCCESS)
  1391. {
  1392. dwErr = ConvertToAutoInheritSD(pParentSD,
  1393. pOldObjSD,
  1394. TRUE,
  1395. &gRegGenMapping,
  1396. &pUpdatedSD);
  1397. if(dwErr == ERROR_SUCCESS)
  1398. {
  1399. //
  1400. // Now, if we're going to do manual propagation,
  1401. // we'll write out the old SD until we get everyone
  1402. // else updated
  1403. //
  1404. PSECURITY_DESCRIPTOR pWriteSD = pUpdatedSD;
  1405. if(fManualProp == TRUE)
  1406. {
  1407. pWriteSD = pOldObjSD;
  1408. }
  1409. else
  1410. {
  1411. if(SetPrivateObjectSecurity(SeInfo,
  1412. pParentSD,
  1413. &pUpdatedSD,
  1414. &gRegGenMapping,
  1415. hProcessToken) == FALSE)
  1416. {
  1417. dwErr = GetLastError();
  1418. }
  1419. }
  1420. //
  1421. // Reset it...
  1422. //
  1423. if(dwErr == ERROR_SUCCESS)
  1424. {
  1425. dwErr = SetRegistrySecurityInfo(hReg,
  1426. SeInfo,
  1427. NULL,
  1428. pWriteSD);
  1429. }
  1430. }
  1431. }
  1432. else
  1433. {
  1434. pVerifySD = NULL;
  1435. }
  1436. }
  1437. }
  1438. }
  1439. }
  1440. else
  1441. {
  1442. if(dwErr == ERROR_SUCCESS &&
  1443. FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  1444. {
  1445. dwErr = SetRegistrySecurityInfo(hReg,
  1446. SeInfo,
  1447. NULL,
  1448. pSD);
  1449. }
  1450. }
  1451. //
  1452. // Ok, now if we're doing propagation, we'll get busy and do that...
  1453. //
  1454. if(dwErr == ERROR_SUCCESS && fManualProp == TRUE)
  1455. {
  1456. //
  1457. // Set our protected flags. If we aren't messing with a particular acl, we'll
  1458. // pretend it's protected
  1459. //
  1460. fProtected = ((SECURITY_DESCRIPTOR *)pUpdatedSD)->Control &
  1461. ~(SE_DACL_PROTECTED | SE_SACL_PROTECTED);
  1462. if(FLAG_ON(fProtected, SE_DACL_PROTECTED ) || FLAG_ON(fProtected, SE_SACL_PROTECTED ))
  1463. {
  1464. dwErr = InsertPropagationFailureEntry(FailureLogList,
  1465. 0,
  1466. fProtected,
  1467. pwszPath == NULL ?
  1468. L"<Unkown Registry Root>" :
  1469. pwszPath);
  1470. }
  1471. if(!FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
  1472. {
  1473. fProtected |= SE_DACL_PROTECTED;
  1474. }
  1475. if(!FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
  1476. {
  1477. fProtected |= SE_SACL_PROTECTED;
  1478. }
  1479. //
  1480. // Ok, go ahead and do deep. This will possibly save us
  1481. // some storage space in the long run...
  1482. //
  1483. dwErr = PropagateRegRightsDeep(pOldObjSD,
  1484. pUpdatedSD,
  1485. SeInfo,
  1486. hReg,
  1487. pcProcessed,
  1488. pfStopFlag,
  1489. fProtected,
  1490. hProcessToken,
  1491. FailureLogList);
  1492. if(dwErr == ERROR_ACCESS_DENIED)
  1493. {
  1494. dwErr = InsertPropagationFailureEntry(FailureLogList,
  1495. dwErr,
  1496. 0,
  1497. pwszPath == NULL ?
  1498. L"<Unkown Registry Root>" :
  1499. pwszPath);
  1500. }
  1501. //
  1502. // If that worked, write out our updated root security descriptor
  1503. //
  1504. if(dwErr == ERROR_SUCCESS)
  1505. {
  1506. PSECURITY_DESCRIPTOR pSet;
  1507. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION))
  1508. {
  1509. if(!SetSecurityDescriptorOwner(pSD, pOwner, FALSE))
  1510. {
  1511. dwErr = GetLastError();
  1512. }
  1513. }
  1514. if(!FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  1515. {
  1516. if(!SetSecurityDescriptorGroup(pSD, pGroup, FALSE))
  1517. {
  1518. dwErr = GetLastError();
  1519. }
  1520. }
  1521. if(dwErr == ERROR_SUCCESS)
  1522. {
  1523. if(CreatePrivateObjectSecurityEx(pParentSD,
  1524. pSD,
  1525. &pSet,
  1526. NULL,
  1527. TRUE,
  1528. SEF_DACL_AUTO_INHERIT |
  1529. SEF_SACL_AUTO_INHERIT |
  1530. SEF_AVOID_OWNER_CHECK |
  1531. SEF_AVOID_PRIVILEGE_CHECK,
  1532. hProcessToken,
  1533. &gRegGenMapping) == FALSE)
  1534. {
  1535. dwErr = GetLastError();
  1536. }
  1537. else
  1538. {
  1539. dwErr = SetRegistrySecurityInfo(hReg,
  1540. SeInfo,
  1541. NULL,
  1542. pSet);
  1543. DestroyPrivateObjectSecurity(&pSet);
  1544. }
  1545. }
  1546. }
  1547. }
  1548. if(dwErr == ERROR_SUCCESS)
  1549. {
  1550. dwErr = WritePropagationFailureList(MARTAEVT_REGISTRY_PROPAGATION_FAILED,
  1551. FailureLogList,
  1552. hProcessToken);
  1553. }
  1554. RegCleanup:
  1555. AccFree(pOldObjSD);
  1556. AccFree(pVerifySD);
  1557. if(pUpdatedSD != NULL)
  1558. {
  1559. DestroyPrivateObjectSecurity(&pUpdatedSD);
  1560. }
  1561. acDebugOut((DEB_TRACE, "Out SetAndPropRegRights: %ld\n", dwErr));
  1562. return(dwErr);
  1563. }
  1564. //+---------------------------------------------------------------------------
  1565. //
  1566. // Function: ConvertRegHandleToName
  1567. //
  1568. // Synopsis: Determines the registry path for a handle. Issues an
  1569. // NtQueryInformationFile to determine the path name
  1570. //
  1571. // Arguments: [IN hKey] -- The (open) handle of the file
  1572. // object
  1573. // [OUT ppwszName] -- Where the name is returned
  1574. //
  1575. // Returns: ERROR_SUCCESS -- Succcess
  1576. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1577. //
  1578. // Notes: The returned memory must be freed with AccFree
  1579. //
  1580. //----------------------------------------------------------------------------
  1581. DWORD
  1582. ConvertRegHandleToName(IN HKEY hKey,
  1583. OUT PWSTR *ppwszName)
  1584. {
  1585. DWORD dwErr = ERROR_SUCCESS;
  1586. //
  1587. // First, determine the size of the buffer we need...
  1588. //
  1589. BYTE pBuff[512];
  1590. ULONG cLen = 0;
  1591. POBJECT_NAME_INFORMATION pNI = NULL;
  1592. PWSTR pwszPath = NULL;
  1593. NTSTATUS Status = NtQueryObject(hKey,
  1594. ObjectNameInformation,
  1595. (POBJECT_NAME_INFORMATION)pBuff,
  1596. 512,
  1597. &cLen);
  1598. if(!NT_SUCCESS(Status))
  1599. {
  1600. if(Status == STATUS_BUFFER_TOO_SMALL ||
  1601. Status == STATUS_INFO_LENGTH_MISMATCH)
  1602. {
  1603. //
  1604. // Fine.. Allocate a big enough buffer
  1605. //
  1606. pNI = (POBJECT_NAME_INFORMATION)AccAlloc(cLen);
  1607. if(pNI != NULL)
  1608. {
  1609. Status = NtQueryObject(hKey,
  1610. ObjectNameInformation,
  1611. pNI,
  1612. cLen,
  1613. NULL);
  1614. if(NT_SUCCESS(Status))
  1615. {
  1616. pwszPath = pNI->Name.Buffer;
  1617. }
  1618. AccFree(pNI);
  1619. }
  1620. else
  1621. {
  1622. Status = STATUS_NO_MEMORY;
  1623. }
  1624. }
  1625. if(dwErr == ERROR_SUCCESS)
  1626. {
  1627. dwErr = RtlNtStatusToDosError(Status);
  1628. }
  1629. }
  1630. else
  1631. {
  1632. pwszPath = ((POBJECT_NAME_INFORMATION)pBuff)->Name.Buffer;
  1633. }
  1634. //
  1635. // If we have a path, then it's a simple matter to pull out the appropriate string,
  1636. // since what gets returned is something in the form of \\REGISTRY\\MACHINE\\somepath
  1637. // which is pretty close to what we want
  1638. //
  1639. #define REG_OBJ_TAG L"\\REGISTRY\\"
  1640. if(pwszPath != NULL)
  1641. {
  1642. pwszPath += (sizeof(REG_OBJ_TAG) / sizeof(WCHAR) - 1);
  1643. ACC_ALLOC_AND_COPY_STRINGW(pwszPath,
  1644. *ppwszName,
  1645. dwErr);
  1646. }
  1647. return(dwErr);
  1648. }