Windows2000/private/ispu/pkitrust/initpki/initacl.cpp

594 lines
15 KiB
C++

// 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;
}