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.

599 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995 - 1999
  5. //
  6. // File: initacl.cpp
  7. //
  8. // Contents: Initialize ACLs so that Everyone only has KEY_READ access
  9. // for the following REGPATHs:
  10. // HKLM\Software\Microsoft\Cryptography\OID ..
  11. // HKLM\Software\Microsoft\Cryptography\Providers\Trust ..
  12. // HKLM\Software\Microsoft\Cryptography\Services ...
  13. // HKLM\Software\Microsoft\SystemCertificates ..
  14. // HKLM\Software\Policies\Microsoft\SystemCertificates ..
  15. // HKLM\Software\Microsoft\EnterpriseCertificates ..
  16. //
  17. // Initialize ACLS so that Everyone has KEY_READ and KEY_SET_VALUE
  18. // access for the following REGPATH:
  19. // HKLM\Software\Microsoft\Cryptography\IEDirtyFlags
  20. //
  21. // Functions: InitializeHKLMAcls
  22. //
  23. // Note: By default HKLM\Software ... gives Everyone special access.
  24. // Special access includes: KEY_READ, KEY_WRITE, DELETE
  25. //
  26. // History: 08-May-98 philh created
  27. //--------------------------------------------------------------------------
  28. #include "global.hxx"
  29. #ifdef STATIC
  30. #undef STATIC
  31. #endif
  32. #define STATIC
  33. static const LPCWSTR rgpwszHKLMRegPath[] = {
  34. OID_REGPATH,
  35. PROVIDERS_REGPATH,
  36. SERVICES_REGPATH,
  37. SYSTEM_STORE_REGPATH,
  38. GROUP_POLICY_STORE_REGPATH,
  39. ENTERPRISE_STORE_REGPATH,
  40. };
  41. #define HKLM_REGPATH_CNT (sizeof(rgpwszHKLMRegPath) / \
  42. sizeof(rgpwszHKLMRegPath[0]))
  43. //+-------------------------------------------------------------------------
  44. // Predefined SIDs allocated once by GetPredefinedSids. Freed when
  45. // InitializeHKLMAcls() returns
  46. //--------------------------------------------------------------------------
  47. static PSID psidLocalSystem = NULL;
  48. static PSID psidAdministrators = NULL;
  49. static PSID psidEveryone = NULL;
  50. //+-------------------------------------------------------------------------
  51. // ACL definitions used to set security on the HKLM registry keys
  52. //--------------------------------------------------------------------------
  53. #define HKLM_SYSTEM_ACE_MASK KEY_ALL_ACCESS
  54. #define HKLM_ADMIN_ACE_MASK KEY_ALL_ACCESS
  55. #define HKLM_EVERYONE_ACE_MASK KEY_READ
  56. #define HKLM_ACE_FLAGS CONTAINER_INHERIT_ACE
  57. #define HKLM_ACE_COUNT 3
  58. #define HKLM_SYSTEM_ACE_INDEX 0
  59. #define HKLM_ADMIN_ACE_INDEX 1
  60. #define HKLM_EVERYONE_ACE_INDEX 2
  61. //+-------------------------------------------------------------------------
  62. // Maximum allowed access rights for Everyone in HKLM
  63. //--------------------------------------------------------------------------
  64. #define MAX_HKLM_EVERYONE_ACE_MASK (KEY_READ | GENERIC_READ)
  65. //+-------------------------------------------------------------------------
  66. // Access rights for Everyone on the CERT_IE_DIRTY_FLAGS registry SubKey
  67. //--------------------------------------------------------------------------
  68. #define IE_EVERYONE_ACE_MASK (KEY_READ | KEY_SET_VALUE)
  69. //+-------------------------------------------------------------------------
  70. // Allocate/free predefined SIDs
  71. //--------------------------------------------------------------------------
  72. STATIC BOOL GetPredefinedSids()
  73. {
  74. BOOL fResult;
  75. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  76. SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority =
  77. SECURITY_WORLD_SID_AUTHORITY;
  78. if (!AllocateAndInitializeSid(
  79. &siaNtAuthority,
  80. 1,
  81. SECURITY_LOCAL_SYSTEM_RID,
  82. 0, 0, 0, 0, 0, 0, 0,
  83. &psidLocalSystem
  84. ))
  85. goto AllocateAndInitializeSidError;
  86. if (!AllocateAndInitializeSid(
  87. &siaNtAuthority,
  88. 2,
  89. SECURITY_BUILTIN_DOMAIN_RID,
  90. DOMAIN_ALIAS_RID_ADMINS,
  91. 0, 0, 0, 0, 0, 0,
  92. &psidAdministrators
  93. ))
  94. goto AllocateAndInitializeSidError;
  95. if (!AllocateAndInitializeSid(
  96. &siaWorldSidAuthority,
  97. 1,
  98. SECURITY_WORLD_RID,
  99. 0, 0, 0, 0, 0, 0, 0,
  100. &psidEveryone
  101. ))
  102. goto AllocateAndInitializeSidError;
  103. fResult = TRUE;
  104. CommonReturn:
  105. return fResult;
  106. ErrorReturn:
  107. fResult = FALSE;
  108. goto CommonReturn;
  109. TRACE_ERROR(AllocateAndInitializeSidError)
  110. }
  111. STATIC void FreePredefinedSids()
  112. {
  113. FreeSid(psidLocalSystem);
  114. FreeSid(psidAdministrators);
  115. FreeSid(psidEveryone);
  116. }
  117. #define HKLM_SD_LEN 0x1000
  118. //+-------------------------------------------------------------------------
  119. // Allocate and get the security descriptor information for the specified
  120. // registry key.
  121. //--------------------------------------------------------------------------
  122. STATIC PSECURITY_DESCRIPTOR AllocAndGetSecurityDescriptor(
  123. IN HKEY hKey,
  124. SECURITY_INFORMATION SecInf
  125. )
  126. {
  127. LONG err;
  128. PSECURITY_DESCRIPTOR psd = NULL;
  129. DWORD cbsd;
  130. cbsd = HKLM_SD_LEN;
  131. if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd)))
  132. goto OutOfMemory;
  133. err = RegGetKeySecurity(
  134. hKey,
  135. SecInf,
  136. psd,
  137. &cbsd
  138. );
  139. if (ERROR_SUCCESS == err)
  140. goto CommonReturn;
  141. if (ERROR_INSUFFICIENT_BUFFER != err)
  142. goto RegGetKeySecurityError;
  143. if (0 == cbsd)
  144. goto NoSecurityDescriptor;
  145. PkiFree(psd);
  146. if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd)))
  147. goto OutOfMemory;
  148. if (ERROR_SUCCESS != (err = RegGetKeySecurity(
  149. hKey,
  150. SecInf,
  151. psd,
  152. &cbsd
  153. ))) goto RegGetKeySecurityError;
  154. CommonReturn:
  155. return psd;
  156. ErrorReturn:
  157. PkiFree(psd);
  158. psd = NULL;
  159. goto CommonReturn;
  160. TRACE_ERROR(OutOfMemory)
  161. SET_ERROR_VAR(RegGetKeySecurityError, err)
  162. SET_ERROR(NoSecurityDescriptor, ERROR_INVALID_SECURITY_DESCR)
  163. }
  164. //+-------------------------------------------------------------------------
  165. // Checks that "Everyone" doesn't have more than KEY_READ or GENERIC_READ
  166. // access rights. If valid, returns TRUE.
  167. //--------------------------------------------------------------------------
  168. STATIC BOOL IsValidHKLMAccessRights(
  169. IN HKEY hKey
  170. )
  171. {
  172. BOOL fResult;
  173. PSECURITY_DESCRIPTOR psd = NULL;
  174. BOOL fDaclPresent;
  175. PACL pAcl; // not allocated
  176. BOOL fDaclDefaulted;
  177. DWORD dwAceIndex;
  178. if (NULL == (psd = AllocAndGetSecurityDescriptor(
  179. hKey,
  180. DACL_SECURITY_INFORMATION
  181. ))) goto GetSecurityDescriptorError;
  182. if (!GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAcl,
  183. &fDaclDefaulted))
  184. goto GetSecurityDescriptorDaclError;
  185. if (!fDaclPresent || NULL == pAcl || 0 == pAcl->AceCount)
  186. goto MissingDaclError;
  187. for (dwAceIndex = 0; dwAceIndex < pAcl->AceCount; dwAceIndex++) {
  188. PACCESS_ALLOWED_ACE pAce;
  189. if (!GetAce(pAcl, dwAceIndex, (void **) &pAce))
  190. goto GetAceError;
  191. if (ACCESS_ALLOWED_ACE_TYPE != pAce->Header.AceType)
  192. continue;
  193. if (!EqualSid(psidEveryone, (PSID) &pAce->SidStart))
  194. continue;
  195. if (0 != (pAce->Mask & ~MAX_HKLM_EVERYONE_ACE_MASK))
  196. goto InvalidEveryoneAccess;
  197. }
  198. fResult = TRUE;
  199. CommonReturn:
  200. PkiFree(psd);
  201. return fResult;
  202. InvalidEveryoneAccess:
  203. ErrorReturn:
  204. fResult = FALSE;
  205. goto CommonReturn;
  206. TRACE_ERROR(GetSecurityDescriptorError)
  207. TRACE_ERROR(GetSecurityDescriptorDaclError)
  208. SET_ERROR(MissingDaclError, ERROR_INVALID_ACL)
  209. TRACE_ERROR(GetAceError)
  210. }
  211. //+-------------------------------------------------------------------------
  212. // Create the SecurityDescriptor to be used for HKLM SubKeys
  213. //--------------------------------------------------------------------------
  214. STATIC BOOL CreateHKLMSecurityDescriptor(
  215. IN ACCESS_MASK EveryoneAccessMask,
  216. OUT PSECURITY_DESCRIPTOR psd,
  217. OUT PACL *ppDacl
  218. )
  219. {
  220. BOOL fResult;
  221. PACL pDacl = NULL;
  222. PACCESS_ALLOWED_ACE pAce;
  223. DWORD dwAclSize;
  224. DWORD i;
  225. if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
  226. goto InitializeSecurityDescriptorError;
  227. // Set DACL
  228. //
  229. // compute size of ACL
  230. //
  231. dwAclSize = sizeof(ACL) +
  232. HKLM_ACE_COUNT * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  233. GetLengthSid(psidLocalSystem) +
  234. GetLengthSid(psidAdministrators) +
  235. GetLengthSid(psidEveryone)
  236. ;
  237. //
  238. // allocate storage for Acl
  239. //
  240. if (NULL == (pDacl = (PACL) PkiNonzeroAlloc(dwAclSize)))
  241. goto OutOfMemory;
  242. if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
  243. goto InitializeAclError;
  244. if (!AddAccessAllowedAce(
  245. pDacl,
  246. ACL_REVISION,
  247. HKLM_SYSTEM_ACE_MASK,
  248. psidLocalSystem
  249. ))
  250. goto AddAceError;
  251. if (!AddAccessAllowedAce(
  252. pDacl,
  253. ACL_REVISION,
  254. HKLM_ADMIN_ACE_MASK,
  255. psidAdministrators
  256. ))
  257. goto AddAceError;
  258. if (!AddAccessAllowedAce(
  259. pDacl,
  260. ACL_REVISION,
  261. EveryoneAccessMask,
  262. psidEveryone
  263. ))
  264. goto AddAceError;
  265. //
  266. // make containers inherit.
  267. //
  268. for (i = 0; i < HKLM_ACE_COUNT; i++) {
  269. if(!GetAce(pDacl, i, (void **) &pAce))
  270. goto GetAceError;
  271. pAce->Header.AceFlags = HKLM_ACE_FLAGS;
  272. }
  273. if (!SetSecurityDescriptorDacl(psd, TRUE, pDacl, FALSE))
  274. goto SetSecurityDescriptorDaclError;
  275. fResult = TRUE;
  276. CommonReturn:
  277. *ppDacl = pDacl;
  278. return fResult;
  279. ErrorReturn:
  280. PkiFree(pDacl);
  281. pDacl = NULL;
  282. fResult = FALSE;
  283. goto CommonReturn;
  284. TRACE_ERROR(InitializeSecurityDescriptorError)
  285. TRACE_ERROR(OutOfMemory)
  286. TRACE_ERROR(InitializeAclError)
  287. TRACE_ERROR(AddAceError)
  288. TRACE_ERROR(GetAceError)
  289. TRACE_ERROR(SetSecurityDescriptorDaclError)
  290. }
  291. //+-------------------------------------------------------------------------
  292. // Set the DACL for the SubKey
  293. //--------------------------------------------------------------------------
  294. STATIC BOOL SetHKLMDacl(
  295. IN HKEY hKey,
  296. IN PSECURITY_DESCRIPTOR psd
  297. )
  298. {
  299. BOOL fResult;
  300. LONG err;
  301. if (ERROR_SUCCESS != (err = RegSetKeySecurity(
  302. hKey,
  303. DACL_SECURITY_INFORMATION,
  304. psd
  305. )))
  306. goto RegSetKeySecurityError;
  307. fResult = TRUE;
  308. CommonReturn:
  309. return fResult;
  310. ErrorReturn:
  311. fResult = FALSE;
  312. goto CommonReturn;
  313. SET_ERROR_VAR(RegSetKeySecurityError, err)
  314. }
  315. STATIC BOOL GetSubKeyInfo(
  316. IN HKEY hKey,
  317. OUT OPTIONAL DWORD *pcSubKeys,
  318. OUT OPTIONAL DWORD *pcchMaxSubKey = NULL
  319. )
  320. {
  321. BOOL fResult;
  322. LONG err;
  323. if (ERROR_SUCCESS != (err = RegQueryInfoKeyU(
  324. hKey,
  325. NULL, // lpszClass
  326. NULL, // lpcchClass
  327. NULL, // lpdwReserved
  328. pcSubKeys,
  329. pcchMaxSubKey,
  330. NULL, // lpcchMaxClass
  331. NULL, // lpcValues
  332. NULL, // lpcchMaxValuesName
  333. NULL, // lpcbMaxValueData
  334. NULL, // lpcbSecurityDescriptor
  335. NULL // lpftLastWriteTime
  336. ))) goto RegQueryInfoKeyError;
  337. fResult = TRUE;
  338. CommonReturn:
  339. // For Win95 Remote Registry Access:: returns half of the cch
  340. if (pcchMaxSubKey && *pcchMaxSubKey)
  341. *pcchMaxSubKey = (*pcchMaxSubKey + 1) * 2 + 2;
  342. return fResult;
  343. ErrorReturn:
  344. fResult = FALSE;
  345. if (pcSubKeys)
  346. *pcSubKeys = 0;
  347. if (pcchMaxSubKey)
  348. *pcchMaxSubKey = 0;
  349. goto CommonReturn;
  350. SET_ERROR_VAR(RegQueryInfoKeyError, err)
  351. }
  352. //+-------------------------------------------------------------------------
  353. // Check the HKEY for valid access rights for Everyone. If not valid, set
  354. // the HKEY's DACL. Enumerate the HKEY's SubKeys and recursively call.
  355. //--------------------------------------------------------------------------
  356. STATIC BOOL RecursiveInitializeHKLMSubKeyAcls(
  357. IN HKEY hKey,
  358. IN PSECURITY_DESCRIPTOR psd
  359. )
  360. {
  361. BOOL fResult = TRUE;
  362. DWORD cSubKeys;
  363. DWORD cchMaxSubKey;
  364. LPWSTR pwszSubKey = NULL;
  365. if (!IsValidHKLMAccessRights(hKey))
  366. fResult &= SetHKLMDacl(hKey, psd);
  367. if (!GetSubKeyInfo(
  368. hKey,
  369. &cSubKeys,
  370. &cchMaxSubKey
  371. ))
  372. return FALSE;
  373. if (cSubKeys && cchMaxSubKey) {
  374. DWORD i;
  375. cchMaxSubKey++;
  376. if (NULL == (pwszSubKey = (LPWSTR) PkiNonzeroAlloc(
  377. cchMaxSubKey * sizeof(WCHAR))))
  378. goto OutOfMemory;
  379. for (i = 0; i < cSubKeys; i++) {
  380. DWORD cchSubKey = cchMaxSubKey;
  381. LONG err;
  382. HKEY hSubKey;
  383. if (ERROR_SUCCESS != (err = RegEnumKeyExU(
  384. hKey,
  385. i,
  386. pwszSubKey,
  387. &cchSubKey,
  388. NULL, // lpdwReserved
  389. NULL, // lpszClass
  390. NULL, // lpcchClass
  391. NULL // lpftLastWriteTime
  392. )) || 0 == cchSubKey ||
  393. L'\0' == *pwszSubKey)
  394. continue;
  395. if (ERROR_SUCCESS != (err = RegOpenKeyExU(
  396. hKey,
  397. pwszSubKey,
  398. 0, // dwReserved
  399. KEY_READ | WRITE_DAC,
  400. &hSubKey))) {
  401. #if DBG
  402. DbgPrintf(DBG_SS_CRYPT32,
  403. "RegOpenKeyEx(%S) returned error: %d 0x%x\n",
  404. pwszSubKey, err, err);
  405. #endif
  406. } else {
  407. fResult &= RecursiveInitializeHKLMSubKeyAcls(hSubKey, psd);
  408. RegCloseKey(hSubKey);
  409. }
  410. }
  411. }
  412. CommonReturn:
  413. PkiFree(pwszSubKey);
  414. return fResult;
  415. ErrorReturn:
  416. fResult = FALSE;
  417. goto CommonReturn;
  418. TRACE_ERROR(OutOfMemory)
  419. }
  420. //+-------------------------------------------------------------------------
  421. // Initialize the HKLM registry used by crypt32 so that Everyone only has
  422. // KEY_READ access rights.
  423. //
  424. // Initialize the IEDirtyFlags registry key so that Everyone has KEY_READ
  425. // and KEY_SET_VALUE access rights.
  426. //--------------------------------------------------------------------------
  427. BOOL
  428. InitializeHKLMAcls()
  429. {
  430. BOOL fResult = TRUE;
  431. SECURITY_DESCRIPTOR sd;
  432. PACL pDacl = NULL;
  433. SECURITY_ATTRIBUTES SecAttr;
  434. HKEY hKey;
  435. LONG err;
  436. DWORD dwDisposition;
  437. DWORD i;
  438. if (!FIsWinNT())
  439. return TRUE;
  440. if (!GetPredefinedSids())
  441. return FALSE;
  442. if (!CreateHKLMSecurityDescriptor(
  443. HKLM_EVERYONE_ACE_MASK,
  444. &sd,
  445. &pDacl
  446. ))
  447. goto ErrorReturn;
  448. memset(&SecAttr, 0, sizeof(SecAttr));
  449. SecAttr.nLength = sizeof(SecAttr);
  450. SecAttr.lpSecurityDescriptor = (LPVOID) &sd;
  451. SecAttr.bInheritHandle = FALSE;
  452. // Iterate through the HKLM registry locations used by crypt32. If
  453. // the registry key doesn't exist, create it and give Everyone READ_KEY
  454. // access. Otherwise, recurse through its SubKeys. For SubKeys having
  455. // more than KEY_READ access rights for Everyone, set their ACLs giving
  456. // only KEY_READ access to Everyone.
  457. for (i = 0; i < HKLM_REGPATH_CNT; i++) {
  458. if (ERROR_SUCCESS != (err = RegCreateKeyExU(
  459. HKEY_LOCAL_MACHINE,
  460. rgpwszHKLMRegPath[i],
  461. 0, // dwReserved
  462. NULL, // lpClass
  463. REG_OPTION_NON_VOLATILE,
  464. MAXIMUM_ALLOWED,
  465. &SecAttr,
  466. &hKey,
  467. &dwDisposition))) {
  468. #if DBG
  469. DbgPrintf(DBG_SS_CRYPT32,
  470. "RegCreateKeyEx(HKLM\\%S) returned error: %d 0x%x\n",
  471. rgpwszHKLMRegPath[i], err, err);
  472. #endif
  473. fResult = FALSE;
  474. continue;
  475. }
  476. if (REG_CREATED_NEW_KEY != dwDisposition)
  477. fResult &= RecursiveInitializeHKLMSubKeyAcls(hKey, &sd);
  478. RegCloseKey(hKey);
  479. }
  480. PkiFree(pDacl);
  481. // Allow Everyone to have KEY_READ and KEY_SET_VALUE access to
  482. // the IEDirtyFlags registry key
  483. if (!CreateHKLMSecurityDescriptor(
  484. IE_EVERYONE_ACE_MASK,
  485. &sd,
  486. &pDacl
  487. ))
  488. goto ErrorReturn;
  489. if (ERROR_SUCCESS != (err = RegCreateKeyExU(
  490. HKEY_LOCAL_MACHINE,
  491. CERT_IE_DIRTY_FLAGS_REGPATH,
  492. 0, // dwReserved
  493. NULL, // lpClass
  494. REG_OPTION_NON_VOLATILE,
  495. MAXIMUM_ALLOWED,
  496. &SecAttr,
  497. &hKey,
  498. &dwDisposition))) {
  499. #if DBG
  500. DbgPrintf(DBG_SS_CRYPT32,
  501. "RegCreateKeyEx(HKLM\\%S) returned error: %d 0x%x\n",
  502. CERT_IE_DIRTY_FLAGS_REGPATH, err, err);
  503. #endif
  504. fResult = FALSE;
  505. } else {
  506. if (REG_CREATED_NEW_KEY != dwDisposition)
  507. fResult &= SetHKLMDacl(hKey, &sd);
  508. RegCloseKey(hKey);
  509. }
  510. PkiFree(pDacl);
  511. CommonReturn:
  512. FreePredefinedSids();
  513. return fResult;
  514. ErrorReturn:
  515. fResult = FALSE;
  516. goto CommonReturn;
  517. }