|
|
//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: initacl.cpp
//
// Contents: Initialize ACLs so that Everyone only has KEY_READ access
// for the following REGPATHs:
// HKLM\Software\Microsoft\Cryptography\OID ..
// HKLM\Software\Microsoft\Cryptography\Providers\Trust ..
// HKLM\Software\Microsoft\Cryptography\Services ...
// HKLM\Software\Microsoft\SystemCertificates ..
// HKLM\Software\Policies\Microsoft\SystemCertificates ..
// HKLM\Software\Microsoft\EnterpriseCertificates ..
//
// Initialize ACLS so that Everyone has KEY_READ and KEY_SET_VALUE
// access for the following REGPATH:
// HKLM\Software\Microsoft\Cryptography\IEDirtyFlags
//
// Functions: InitializeHKLMAcls
//
// Note: By default HKLM\Software ... gives Everyone special access.
// Special access includes: KEY_READ, KEY_WRITE, DELETE
//
// History: 08-May-98 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
static const LPCWSTR rgpwszHKLMRegPath[] = { OID_REGPATH, PROVIDERS_REGPATH, SERVICES_REGPATH, SYSTEM_STORE_REGPATH, GROUP_POLICY_STORE_REGPATH, ENTERPRISE_STORE_REGPATH, };
#define HKLM_REGPATH_CNT (sizeof(rgpwszHKLMRegPath) / \
sizeof(rgpwszHKLMRegPath[0]))
//+-------------------------------------------------------------------------
// Predefined SIDs allocated once by GetPredefinedSids. Freed when
// InitializeHKLMAcls() returns
//--------------------------------------------------------------------------
static PSID psidLocalSystem = NULL; static PSID psidAdministrators = NULL; static PSID psidEveryone = NULL;
//+-------------------------------------------------------------------------
// ACL definitions used to set security on the HKLM registry keys
//--------------------------------------------------------------------------
#define HKLM_SYSTEM_ACE_MASK KEY_ALL_ACCESS
#define HKLM_ADMIN_ACE_MASK KEY_ALL_ACCESS
#define HKLM_EVERYONE_ACE_MASK KEY_READ
#define HKLM_ACE_FLAGS CONTAINER_INHERIT_ACE
#define HKLM_ACE_COUNT 3
#define HKLM_SYSTEM_ACE_INDEX 0
#define HKLM_ADMIN_ACE_INDEX 1
#define HKLM_EVERYONE_ACE_INDEX 2
//+-------------------------------------------------------------------------
// Maximum allowed access rights for Everyone in HKLM
//--------------------------------------------------------------------------
#define MAX_HKLM_EVERYONE_ACE_MASK (KEY_READ | GENERIC_READ)
//+-------------------------------------------------------------------------
// Access rights for Everyone on the CERT_IE_DIRTY_FLAGS registry SubKey
//--------------------------------------------------------------------------
#define IE_EVERYONE_ACE_MASK (KEY_READ | KEY_SET_VALUE)
//+-------------------------------------------------------------------------
// Allocate/free predefined SIDs
//--------------------------------------------------------------------------
STATIC BOOL GetPredefinedSids() { BOOL fResult; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
if (!AllocateAndInitializeSid( &siaNtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidLocalSystem )) goto AllocateAndInitializeSidError;
if (!AllocateAndInitializeSid( &siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators )) goto AllocateAndInitializeSidError;
if (!AllocateAndInitializeSid( &siaWorldSidAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone )) goto AllocateAndInitializeSidError;
fResult = TRUE; CommonReturn: return fResult;
ErrorReturn: fResult = FALSE; goto CommonReturn; TRACE_ERROR(AllocateAndInitializeSidError) }
STATIC void FreePredefinedSids() { FreeSid(psidLocalSystem); FreeSid(psidAdministrators); FreeSid(psidEveryone);
}
#define HKLM_SD_LEN 0x1000
//+-------------------------------------------------------------------------
// Allocate and get the security descriptor information for the specified
// registry key.
//--------------------------------------------------------------------------
STATIC PSECURITY_DESCRIPTOR AllocAndGetSecurityDescriptor( IN HKEY hKey, SECURITY_INFORMATION SecInf ) { LONG err; PSECURITY_DESCRIPTOR psd = NULL; DWORD cbsd;
cbsd = HKLM_SD_LEN; if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd))) goto OutOfMemory;
err = RegGetKeySecurity( hKey, SecInf, psd, &cbsd ); if (ERROR_SUCCESS == err) goto CommonReturn; if (ERROR_INSUFFICIENT_BUFFER != err) goto RegGetKeySecurityError;
if (0 == cbsd) goto NoSecurityDescriptor;
PkiFree(psd); if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd))) goto OutOfMemory;
if (ERROR_SUCCESS != (err = RegGetKeySecurity( hKey, SecInf, psd, &cbsd ))) goto RegGetKeySecurityError;
CommonReturn: return psd; ErrorReturn: PkiFree(psd); psd = NULL; goto CommonReturn;
TRACE_ERROR(OutOfMemory) SET_ERROR_VAR(RegGetKeySecurityError, err) SET_ERROR(NoSecurityDescriptor, ERROR_INVALID_SECURITY_DESCR) }
//+-------------------------------------------------------------------------
// Checks that "Everyone" doesn't have more than KEY_READ or GENERIC_READ
// access rights. If valid, returns TRUE.
//--------------------------------------------------------------------------
STATIC BOOL IsValidHKLMAccessRights( IN HKEY hKey ) { BOOL fResult; PSECURITY_DESCRIPTOR psd = NULL; BOOL fDaclPresent; PACL pAcl; // not allocated
BOOL fDaclDefaulted; DWORD dwAceIndex;
if (NULL == (psd = AllocAndGetSecurityDescriptor( hKey, DACL_SECURITY_INFORMATION ))) goto GetSecurityDescriptorError;
if (!GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAcl, &fDaclDefaulted)) goto GetSecurityDescriptorDaclError; if (!fDaclPresent || NULL == pAcl || 0 == pAcl->AceCount) goto MissingDaclError;
for (dwAceIndex = 0; dwAceIndex < pAcl->AceCount; dwAceIndex++) { PACCESS_ALLOWED_ACE pAce;
if (!GetAce(pAcl, dwAceIndex, (void **) &pAce)) goto GetAceError;
if (ACCESS_ALLOWED_ACE_TYPE != pAce->Header.AceType) continue; if (!EqualSid(psidEveryone, (PSID) &pAce->SidStart)) continue;
if (0 != (pAce->Mask & ~MAX_HKLM_EVERYONE_ACE_MASK)) goto InvalidEveryoneAccess; }
fResult = TRUE; CommonReturn: PkiFree(psd); return fResult; InvalidEveryoneAccess: ErrorReturn: fResult = FALSE; goto CommonReturn;
TRACE_ERROR(GetSecurityDescriptorError) TRACE_ERROR(GetSecurityDescriptorDaclError) SET_ERROR(MissingDaclError, ERROR_INVALID_ACL) TRACE_ERROR(GetAceError) }
//+-------------------------------------------------------------------------
// Create the SecurityDescriptor to be used for HKLM SubKeys
//--------------------------------------------------------------------------
STATIC BOOL CreateHKLMSecurityDescriptor( IN ACCESS_MASK EveryoneAccessMask, OUT PSECURITY_DESCRIPTOR psd, OUT PACL *ppDacl ) { BOOL fResult; PACL pDacl = NULL; PACCESS_ALLOWED_ACE pAce; DWORD dwAclSize; DWORD i;
if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) goto InitializeSecurityDescriptorError;
// Set DACL
//
// compute size of ACL
//
dwAclSize = sizeof(ACL) + HKLM_ACE_COUNT * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) + GetLengthSid(psidLocalSystem) + GetLengthSid(psidAdministrators) + GetLengthSid(psidEveryone) ;
//
// allocate storage for Acl
//
if (NULL == (pDacl = (PACL) PkiNonzeroAlloc(dwAclSize))) goto OutOfMemory;
if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION)) goto InitializeAclError;
if (!AddAccessAllowedAce( pDacl, ACL_REVISION, HKLM_SYSTEM_ACE_MASK, psidLocalSystem )) goto AddAceError; if (!AddAccessAllowedAce( pDacl, ACL_REVISION, HKLM_ADMIN_ACE_MASK, psidAdministrators )) goto AddAceError; if (!AddAccessAllowedAce( pDacl, ACL_REVISION, EveryoneAccessMask, psidEveryone )) goto AddAceError;
//
// make containers inherit.
//
for (i = 0; i < HKLM_ACE_COUNT; i++) { if(!GetAce(pDacl, i, (void **) &pAce)) goto GetAceError; pAce->Header.AceFlags = HKLM_ACE_FLAGS; }
if (!SetSecurityDescriptorDacl(psd, TRUE, pDacl, FALSE)) goto SetSecurityDescriptorDaclError;
fResult = TRUE; CommonReturn: *ppDacl = pDacl; return fResult; ErrorReturn: PkiFree(pDacl); pDacl = NULL; fResult = FALSE; goto CommonReturn;
TRACE_ERROR(InitializeSecurityDescriptorError) TRACE_ERROR(OutOfMemory) TRACE_ERROR(InitializeAclError) TRACE_ERROR(AddAceError) TRACE_ERROR(GetAceError) TRACE_ERROR(SetSecurityDescriptorDaclError) }
//+-------------------------------------------------------------------------
// Set the DACL for the SubKey
//--------------------------------------------------------------------------
STATIC BOOL SetHKLMDacl( IN HKEY hKey, IN PSECURITY_DESCRIPTOR psd ) { BOOL fResult; LONG err;
if (ERROR_SUCCESS != (err = RegSetKeySecurity( hKey, DACL_SECURITY_INFORMATION, psd ))) goto RegSetKeySecurityError;
fResult = TRUE; CommonReturn: return fResult; ErrorReturn: fResult = FALSE; goto CommonReturn;
SET_ERROR_VAR(RegSetKeySecurityError, err) }
STATIC BOOL GetSubKeyInfo( IN HKEY hKey, OUT OPTIONAL DWORD *pcSubKeys, OUT OPTIONAL DWORD *pcchMaxSubKey = NULL ) { BOOL fResult; LONG err; if (ERROR_SUCCESS != (err = RegQueryInfoKeyU( hKey, NULL, // lpszClass
NULL, // lpcchClass
NULL, // lpdwReserved
pcSubKeys, pcchMaxSubKey, NULL, // lpcchMaxClass
NULL, // lpcValues
NULL, // lpcchMaxValuesName
NULL, // lpcbMaxValueData
NULL, // lpcbSecurityDescriptor
NULL // lpftLastWriteTime
))) goto RegQueryInfoKeyError; fResult = TRUE;
CommonReturn: // For Win95 Remote Registry Access:: returns half of the cch
if (pcchMaxSubKey && *pcchMaxSubKey) *pcchMaxSubKey = (*pcchMaxSubKey + 1) * 2 + 2; return fResult; ErrorReturn: fResult = FALSE; if (pcSubKeys) *pcSubKeys = 0; if (pcchMaxSubKey) *pcchMaxSubKey = 0; goto CommonReturn; SET_ERROR_VAR(RegQueryInfoKeyError, err) }
//+-------------------------------------------------------------------------
// Check the HKEY for valid access rights for Everyone. If not valid, set
// the HKEY's DACL. Enumerate the HKEY's SubKeys and recursively call.
//--------------------------------------------------------------------------
STATIC BOOL RecursiveInitializeHKLMSubKeyAcls( IN HKEY hKey, IN PSECURITY_DESCRIPTOR psd ) { BOOL fResult = TRUE; DWORD cSubKeys; DWORD cchMaxSubKey; LPWSTR pwszSubKey = NULL;
if (!IsValidHKLMAccessRights(hKey)) fResult &= SetHKLMDacl(hKey, psd);
if (!GetSubKeyInfo( hKey, &cSubKeys, &cchMaxSubKey )) return FALSE;
if (cSubKeys && cchMaxSubKey) { DWORD i;
cchMaxSubKey++; if (NULL == (pwszSubKey = (LPWSTR) PkiNonzeroAlloc( cchMaxSubKey * sizeof(WCHAR)))) goto OutOfMemory;
for (i = 0; i < cSubKeys; i++) { DWORD cchSubKey = cchMaxSubKey; LONG err; HKEY hSubKey;
if (ERROR_SUCCESS != (err = RegEnumKeyExU( hKey, i, pwszSubKey, &cchSubKey, NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
)) || 0 == cchSubKey || L'\0' == *pwszSubKey) continue;
if (ERROR_SUCCESS != (err = RegOpenKeyExU( hKey, pwszSubKey, 0, // dwReserved
KEY_READ | WRITE_DAC, &hSubKey))) { #if DBG
DbgPrintf(DBG_SS_CRYPT32, "RegOpenKeyEx(%S) returned error: %d 0x%x\n", pwszSubKey, err, err); #endif
} else { fResult &= RecursiveInitializeHKLMSubKeyAcls(hSubKey, psd); RegCloseKey(hSubKey); } } }
CommonReturn: PkiFree(pwszSubKey); return fResult; ErrorReturn: fResult = FALSE; goto CommonReturn; TRACE_ERROR(OutOfMemory) }
//+-------------------------------------------------------------------------
// Initialize the HKLM registry used by crypt32 so that Everyone only has
// KEY_READ access rights.
//
// Initialize the IEDirtyFlags registry key so that Everyone has KEY_READ
// and KEY_SET_VALUE access rights.
//--------------------------------------------------------------------------
BOOL InitializeHKLMAcls() { BOOL fResult = TRUE; SECURITY_DESCRIPTOR sd; PACL pDacl = NULL; SECURITY_ATTRIBUTES SecAttr;
HKEY hKey; LONG err; DWORD dwDisposition; DWORD i;
if (!FIsWinNT()) return TRUE;
if (!GetPredefinedSids()) return FALSE;
if (!CreateHKLMSecurityDescriptor( HKLM_EVERYONE_ACE_MASK, &sd, &pDacl )) goto ErrorReturn;
memset(&SecAttr, 0, sizeof(SecAttr)); SecAttr.nLength = sizeof(SecAttr); SecAttr.lpSecurityDescriptor = (LPVOID) &sd; SecAttr.bInheritHandle = FALSE;
// Iterate through the HKLM registry locations used by crypt32. If
// the registry key doesn't exist, create it and give Everyone READ_KEY
// access. Otherwise, recurse through its SubKeys. For SubKeys having
// more than KEY_READ access rights for Everyone, set their ACLs giving
// only KEY_READ access to Everyone.
for (i = 0; i < HKLM_REGPATH_CNT; i++) { if (ERROR_SUCCESS != (err = RegCreateKeyExU( HKEY_LOCAL_MACHINE, rgpwszHKLMRegPath[i], 0, // dwReserved
NULL, // lpClass
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, &SecAttr, &hKey, &dwDisposition))) { #if DBG
DbgPrintf(DBG_SS_CRYPT32, "RegCreateKeyEx(HKLM\\%S) returned error: %d 0x%x\n", rgpwszHKLMRegPath[i], err, err); #endif
fResult = FALSE; continue; }
if (REG_CREATED_NEW_KEY != dwDisposition) fResult &= RecursiveInitializeHKLMSubKeyAcls(hKey, &sd);
RegCloseKey(hKey); } PkiFree(pDacl);
// Allow Everyone to have KEY_READ and KEY_SET_VALUE access to
// the IEDirtyFlags registry key
if (!CreateHKLMSecurityDescriptor( IE_EVERYONE_ACE_MASK, &sd, &pDacl )) goto ErrorReturn;
if (ERROR_SUCCESS != (err = RegCreateKeyExU( HKEY_LOCAL_MACHINE, CERT_IE_DIRTY_FLAGS_REGPATH, 0, // dwReserved
NULL, // lpClass
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, &SecAttr, &hKey, &dwDisposition))) { #if DBG
DbgPrintf(DBG_SS_CRYPT32, "RegCreateKeyEx(HKLM\\%S) returned error: %d 0x%x\n", CERT_IE_DIRTY_FLAGS_REGPATH, err, err); #endif
fResult = FALSE; } else { if (REG_CREATED_NEW_KEY != dwDisposition) fResult &= SetHKLMDacl(hKey, &sd); RegCloseKey(hKey); } PkiFree(pDacl);
CommonReturn: FreePredefinedSids(); return fResult; ErrorReturn: fResult = FALSE; goto CommonReturn; }
|