windows-nt/Source/XPSP1/NT/ds/security/services/ca/certlib/casd.cpp

1224 lines
33 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+--------------------------------------------------------------------------
// File: casd.cpp
// Contents: CCertificateAuthoritySD implementation
//---------------------------------------------------------------------------
#include <pch.cpp>
#include <sid.h>
#include <certsd.h>
#include <certacl.h>
#include <prvlg.h>
#include <sid.h>
//
// MessageId: CERTSRV_E_NO_CAADMIN_DEFINED
//
// MessageText:
//
// At least one security principal must have the permission to manage this CA.
//
#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL)
LPCWSTR const *CCertificateAuthoritySD::m_pcwszResources; // no free
using namespace CertSrv;
HRESULT CCertificateAuthoritySD::Set(
const PSECURITY_DESCRIPTOR pSD,
bool fSetDSSecurity)
{
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pSDCrt; // no free
PSECURITY_DESCRIPTOR pSDNew = NULL;
SECURITY_DESCRIPTOR_CONTROL sdc;
CPrivilegeManager PrivilegeMgr;
CSASSERT(NULL != pSD);
hr = LockGet(&pSDCrt);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
hr = myMergeSD(pSDCrt, pSD, DACL_SECURITY_INFORMATION, &pSDNew);
_JumpIfError(hr, error, "myMergeSD");
hr = Unlock();
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Unlock");
hr = CProtectedSecurityDescriptor::Set(pSDNew);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Set");
hr = MapAndSetDaclOnObjects(fSetDSSecurity);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAndSetDaclOnObjects");
error:
LOCAL_FREE(pSDNew);
return hr;
}
HRESULT CCertificateAuthoritySD::MapAndSetDaclOnObjects(bool fSetDSSecurity)
{
HRESULT hr = S_OK;
PACL pCADacl; // no free
PACL pDSAcl = NULL;
PACL pServiceAcl = NULL;
PSECURITY_DESCRIPTOR pCASD; // no free
BOOL fDaclPresent;
ACL_SIZE_INFORMATION CAAclInfo, DefaultDSAclInfo, DefaultServiceAclInfo;
DWORD dwIndex, dwIndex2, dwIndex3;
PVOID pAce;
DWORD dwDSAclSize=0, dwServiceAclSize=0;
DWORD dwTempSize;
hr = LockGet(&pCASD);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
hr = myGetSecurityDescriptorDacl(
pCASD,
&pCADacl);
_JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
if(!GetAclInformation(pCADacl,
&CAAclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
// calculate the DACL size
for(dwIndex = 0; dwIndex < CAAclInfo.AceCount; dwIndex++)
{
if(!GetAce(pCADacl, dwIndex, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(fSetDSSecurity)
{
hr = MapAclGetSize(pAce, ObjType_DS, dwTempSize);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclGetSize");
}
dwDSAclSize += dwTempSize;
hr = MapAclGetSize(pAce, ObjType_Service, dwTempSize);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclGetSize");
dwServiceAclSize += dwTempSize;
}
if(fSetDSSecurity)
{
hr = SetDefaultAcl(ObjType_DS);
_JumpIfError(hr, error, "CCertificateAuthoritySD::SetDefaultAcl");
if(!GetAclInformation(m_pDefaultDSAcl,
&DefaultDSAclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
CSASSERT(0==DefaultDSAclInfo.AclBytesFree);
dwDSAclSize += DefaultDSAclInfo.AclBytesInUse;
pDSAcl = (PACL)LocalAlloc(LMEM_FIXED, dwDSAclSize);
if(!pDSAcl)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!InitializeAcl(pDSAcl, dwDSAclSize, ACL_REVISION_DS ))
{
hr = myHLastError();
_JumpError(hr, error, "InitializeAcl");
}
}
hr = SetDefaultAcl(ObjType_Service);
_JumpIfError(hr, error, "CCertificateAuthoritySD::SetDefaultAcl");
if(!GetAclInformation(m_pDefaultServiceAcl,
&DefaultServiceAclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
CSASSERT(0==DefaultServiceAclInfo.AclBytesFree);
dwServiceAclSize += DefaultServiceAclInfo.AclBytesInUse;
pServiceAcl = (PACL)LocalAlloc(LMEM_FIXED, dwServiceAclSize);
if(!pServiceAcl)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!InitializeAcl(pServiceAcl, dwServiceAclSize, ACL_REVISION))
{
hr = myHLastError();
_JumpError(hr, error, "InitializeAcl");
}
// copy deny aces from default service acl
for(dwIndex = 0; dwIndex < DefaultServiceAclInfo.AceCount; dwIndex++)
{
if(!GetAce(m_pDefaultServiceAcl, dwIndex, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_DENIED_ACE_TYPE)
continue;
if(!AddAce(
pServiceAcl,
ACL_REVISION,
MAXDWORD,
pAce,
((ACE_HEADER*)pAce)->AceSize))
{
hr = myHLastError();
_JumpError(hr, error, "AddAce");
}
}
if(fSetDSSecurity)
{
// copy deny aces from default ds acl
for(dwIndex3 = 0; dwIndex3 < DefaultDSAclInfo.AceCount; dwIndex3++)
{
if(!GetAce(m_pDefaultDSAcl, dwIndex3, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_DENIED_ACE_TYPE &&
((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_DENIED_OBJECT_ACE_TYPE)
continue;
if(!AddAce(
pDSAcl,
ACL_REVISION_DS,
MAXDWORD,
pAce,
((ACE_HEADER*)pAce)->AceSize))
{
hr = myHLastError();
_JumpError(hr, error, "AddAce");
}
}
}
// add mapped deny aces to the DACL
for(dwIndex2 = 0; dwIndex2 < CAAclInfo.AceCount; dwIndex2++)
{
if(!GetAce(pCADacl, dwIndex2, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_DENIED_ACE_TYPE)
continue;
if(fSetDSSecurity)
{
hr = MapAclAddAce(pDSAcl, ObjType_DS, pAce);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclAddAce");
}
hr = MapAclAddAce(pServiceAcl, ObjType_Service, pAce);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclAddAce");
}
// continue with the allow aces from default service acl
for(dwIndex=0; dwIndex < DefaultServiceAclInfo.AceCount; dwIndex++)
{
if(!GetAce(m_pDefaultServiceAcl, dwIndex, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE)
continue;
if(!AddAce(
pServiceAcl,
ACL_REVISION,
MAXDWORD,
pAce,
((ACE_HEADER*)pAce)->AceSize))
{
hr = myHLastError();
_JumpError(hr, error, "AddAce");
}
}
// continue with the allow aces from default ds acl
if(fSetDSSecurity)
{
for(dwIndex3=0; dwIndex3 < DefaultDSAclInfo.AceCount; dwIndex3++)
{
if(!GetAce(m_pDefaultDSAcl, dwIndex3, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE &&
((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_ALLOWED_OBJECT_ACE_TYPE)
continue;
if(!AddAce(
pDSAcl,
ACL_REVISION_DS,
MAXDWORD,
pAce,
((ACE_HEADER*)pAce)->AceSize))
{
hr = myHLastError();
_JumpError(hr, error, "AddAce");
}
}
}
// continue with the allow mapped aces to the DACL
for(dwIndex2=0;dwIndex2 < CAAclInfo.AceCount; dwIndex2++)
{
if(!GetAce(pCADacl, dwIndex2, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE)
{
continue;
}
if(fSetDSSecurity)
{
hr = MapAclAddAce(pDSAcl, ObjType_DS, pAce);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclAddAce");
}
hr = MapAclAddAce(pServiceAcl, ObjType_Service, pAce);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclAddAce");
}
hr = Unlock();
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Unlock");
hr = MapAclSetOnService(pServiceAcl);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclSetOnService");
// set DACL on objects
if(fSetDSSecurity)
{
hr = MapAclSetOnDS(pDSAcl);
_JumpIfError(hr, error, "CCertificateAuthoritySD::MapAclSetOnDS");
}
error:
LOCAL_FREE(pDSAcl);
LOCAL_FREE(pServiceAcl);
return hr;
}
HRESULT CCertificateAuthoritySD::MapAclGetSize(
PVOID pAce,
ObjType type,
DWORD& dwSize)
{
ACCESS_ALLOWED_ACE *pAllowAce = (ACCESS_ALLOWED_ACE*)pAce;
// CA acl should contain only ACCESS_ALLOWED_ACE_TYPE
// and ACCESS_DENIED_ACE_TYPE
if(ACCESS_ALLOWED_ACE_TYPE != pAllowAce->Header.AceType &&
ACCESS_DENIED_ACE_TYPE != pAllowAce->Header.AceType)
{
return E_INVALIDARG;
}
dwSize = 0;
switch(type)
{
case ObjType_DS:
// enroll access maps to enroll object ace on DS
if(pAllowAce->Mask & CA_ACCESS_ENROLL)
{
dwSize = sizeof(ACCESS_ALLOWED_OBJECT_ACE) - sizeof(DWORD)+
GetLengthSid((PSID)&(pAllowAce->SidStart));
}
break;
case ObjType_Service:
// ca admin maps to full control on service
if(pAllowAce->Mask & CA_ACCESS_ADMIN)
{
dwSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)+
GetLengthSid((PSID)&(pAllowAce->SidStart));
}
break;
default:
CSASSERT("Invalid object type" && 0);
}
return S_OK;
}
HRESULT CCertificateAuthoritySD::MapAclAddAce(
PACL pAcl,
ObjType type,
PVOID pAce)
{
ACCESS_ALLOWED_ACE *pCrtAce = (ACCESS_ALLOWED_ACE *)pAce;
bool fAllowAce = (pCrtAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE);
CSASSERT(pCrtAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
pCrtAce->Header.AceType == ACCESS_DENIED_ACE_TYPE);
switch(type)
{
case ObjType_DS:
// enroll access maps to enroll object ace on DS
if(pCrtAce->Mask & CA_ACCESS_ENROLL)
{
if(fAllowAce)
{
if(!AddAccessAllowedObjectAce(
pAcl,
ACL_REVISION_DS,
NO_INHERITANCE,
ACTRL_DS_CONTROL_ACCESS,
const_cast<GUID*>(&GUID_ENROLL),
NULL,
&pCrtAce->SidStart))
{
return myHLastError();
}
}
else
{
if(!AddAccessDeniedObjectAce(
pAcl,
ACL_REVISION_DS,
NO_INHERITANCE,
ACTRL_DS_CONTROL_ACCESS,
const_cast<GUID*>(&GUID_ENROLL),
NULL,
&pCrtAce->SidStart))
{
return myHLastError();
}
}
}
break;
case ObjType_Service:
// ca admin maps to full control on service
if(pCrtAce->Mask & CA_ACCESS_ADMIN)
{
if(fAllowAce)
{
if(!AddAccessAllowedAce(
pAcl,
ACL_REVISION,
SERVICE_ALL_ACCESS,
&pCrtAce->SidStart))
{
return myHLastError();
}
}
else
{
if(!AddAccessDeniedAce(
pAcl,
ACL_REVISION,
SERVICE_ALL_ACCESS,
&pCrtAce->SidStart))
{
return myHLastError();
}
}
}
break;
default:
CSASSERT("Invalid object type" && 0);
}
return S_OK;
}
HRESULT CCertificateAuthoritySD::SetDefaultAcl(ObjType type)
{
HRESULT hr = S_OK;
switch(type)
{
case ObjType_DS:
if(!m_pDefaultDSAcl)
{
hr = SetComputerSID();
_JumpIfError(hr, error, "SetComputerSID");
CSASSERT(!m_pDefaultDSSD);
hr = myGetSDFromTemplate(
WSZ_DEFAULT_DSENROLLMENT_SECURITY,
m_pwszComputerSID,
&m_pDefaultDSSD);
_JumpIfError(hr, error, "myGetSDFromTemplate");
hr = myGetSecurityDescriptorDacl(
m_pDefaultDSSD,
&m_pDefaultDSAcl);
_JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
}
break;
case ObjType_Service:
if(!m_pDefaultServiceAcl)
{
CSASSERT(!m_pDefaultServiceSD);
hr = myGetSDFromTemplate(
WSZ_DEFAULT_SERVICE_SECURITY,
NULL,
&m_pDefaultServiceSD);
_JumpIfError(hr, error, "myGetSDFromTemplate");
hr = myGetSecurityDescriptorDacl(
m_pDefaultServiceSD,
&m_pDefaultServiceAcl);
_JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
}
break;
}
error:
return hr;
}
HRESULT CCertificateAuthoritySD::SetComputerSID()
{
HRESULT hr = S_OK;
LPWSTR pwszDomainName = NULL;
DWORD cDomainName = 0;
LPWSTR pwszComputerName = NULL;
DWORD cbSid;
SID_NAME_USE SidUse;
PBYTE pComputerSID = NULL;
CSASSERT(!m_pwszComputerSID);
hr = myGetComputerObjectName(NameSamCompatible, &pwszComputerName);
_JumpIfError(hr, error, "myGetComputerObjectName");
LookupAccountName(
NULL,
pwszComputerName,
NULL,
&cbSid,
NULL,
&cDomainName,
&SidUse);
if(GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
{
hr = myHLastError();
_JumpError(hr, error, "LookupAccountName");
}
pwszDomainName = (LPWSTR)LocalAlloc(
LMEM_FIXED,
cDomainName*sizeof(WCHAR));
if(!pwszDomainName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pComputerSID = (LPBYTE)LocalAlloc(
LMEM_FIXED,
cbSid);
if(!pComputerSID)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!LookupAccountName(
NULL,
pwszComputerName,
pComputerSID,
&cbSid,
pwszDomainName,
&cDomainName,
&SidUse))
{
hr = myHLastError();
_JumpError(hr, error, "LookupAccountName");
}
if(!myConvertSidToStringSid(
pComputerSID,
&m_pwszComputerSID))
{
hr = myHLastError();
_JumpError(hr, error, "myConvertSidToStringSid");
}
error:
LOCAL_FREE(pwszDomainName);
LOCAL_FREE(pComputerSID);
return hr;
}
typedef LPCWSTR (WINAPI FNCAGETDN)(
IN HCAINFO hCAInfo);
LPCWSTR
myCAGetDN(
IN HCAINFO hCAInfo)
{
HMODULE hModule;
static FNCAGETDN *s_pfn = NULL;
LPCWSTR pwszCADN = NULL;
if (NULL == s_pfn)
{
hModule = GetModuleHandle(TEXT("certcli.dll"));
if (NULL == hModule)
{
goto error;
}
s_pfn = (FNCAGETDN *) GetProcAddress(hModule, "CAGetDN");
if (NULL == s_pfn)
{
goto error;
}
}
pwszCADN = (*s_pfn)(hCAInfo);
error:
return(pwszCADN);
}
HRESULT CCertificateAuthoritySD::MapAclSetOnDS(const PACL pAcl)
{
HRESULT hr = S_OK;
LPWSTR pwszSanitizedDSName = NULL;
HCAINFO hCAInfo;
LPCWSTR pwszCADN;
hr = mySanitizedNameToDSName(m_pcwszSanitizedName, &pwszSanitizedDSName);
_JumpIfError(hr, error, "mySanitizedNameToDSName");
hr = CAFindByName(
pwszSanitizedDSName,
NULL,
CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA,
&hCAInfo);
_JumpIfErrorStr(hr, error, "CAFindByName", pwszSanitizedDSName);
pwszCADN = myCAGetDN(hCAInfo);
if (NULL == pwszCADN)
{
hr = myHLastError();
_JumpError(hr, error, "myCAGetDN");
}
hr = SetNamedSecurityInfo(
const_cast<LPWSTR>(pwszCADN),
SE_DS_OBJECT_ALL,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pAcl,
NULL);
if(ERROR_SUCCESS != hr)
{
if(ERROR_ACCESS_DENIED == hr)
{
// If we can't set the acl on ds enrollment object, notify
// the caller with a special error code so it can take action.
// See bug# 193388
hr = ERROR_CAN_NOT_COMPLETE;
}
hr = myHError(hr);
_JumpError(hr, error, "SetNamedSecurityInfo");
}
error:
LOCAL_FREE(pwszSanitizedDSName);
if(hCAInfo)
CACloseCA(hCAInfo);
return hr;
}
HRESULT CCertificateAuthoritySD::MapAclSetOnService(const PACL pAcl)
{
HRESULT hr = S_OK;
hr = SetNamedSecurityInfo(
wszSERVICE_NAME,
SE_SERVICE,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pAcl,
NULL);
if(ERROR_SUCCESS != hr)
{
hr = myHError(hr);
_JumpError(hr, error, "SetNamedSecurityInfo");
}
error:
return hr;
}
HRESULT CCertificateAuthoritySD::ResetSACL()
{
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pSaclSD = NULL;
PSECURITY_DESCRIPTOR pSDCrt; // no free
PSECURITY_DESCRIPTOR pSDNew = NULL;
hr = myGetSDFromTemplate(
CERTSRV_SACL_ON,
NULL,
&pSaclSD);
_JumpIfError(hr, error, "myGetSDFromTemplate");
hr = LockGet(&pSDCrt);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
hr = myMergeSD(pSDCrt, pSaclSD, SACL_SECURITY_INFORMATION, &pSDNew);
_JumpIfError(hr, error, "myMergeSD");
hr = Unlock();
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Unlock");
hr = CProtectedSecurityDescriptor::Set(pSDNew);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Set");
error:
LOCAL_FREE(pSaclSD);
LOCAL_FREE(pSDNew);
return hr;
}
// Upgrade from CA security descriptor from win2k.
//
// Allow aces are mapped as follows:
// manage -> CA admin + officer
// enroll -> enroll
// read -> read
// revoke -> officer
// approve -> officer
// else -> read
//
// Deny aces are ignored.
HRESULT CCertificateAuthoritySD::UpgradeWin2k(
bool fUseEnterpriseAcl)
{
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pSDOld; // no free
PACL pAclOld; // no free
PSECURITY_DESCRIPTOR pSDNewDaclOnly = NULL;
PSECURITY_DESCRIPTOR pSDNewSaclOnly = NULL;
PSECURITY_DESCRIPTOR pSDNew = NULL;
PACL pAclNew = NULL;
ACL_SIZE_INFORMATION OldAclSizeInfo;
DWORD dwSizeAclNew = sizeof(ACL);
DWORD cAce;
PVOID pAce;
ACCESS_MASK dwAccessMask;
PSID pSid; // no free
hr = LockGet(&pSDOld);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
hr = myGetSecurityDescriptorDacl(
pSDOld,
&pAclOld);
_JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
if(!GetAclInformation(pAclOld,
&OldAclSizeInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
for(cAce=0;cAce<OldAclSizeInfo.AceCount;cAce++)
{
if(!GetAce(pAclOld, cAce, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
dwSizeAclNew += GetUpgradeAceSizeAndType(pAce, NULL, NULL);
}
// if no valid ACE found, fall back to a default SD
if(sizeof(ACL)==dwSizeAclNew)
{
hr= myGetSDFromTemplate(
fUseEnterpriseAcl?
WSZ_DEFAULT_CA_ENT_SECURITY:
WSZ_DEFAULT_CA_STD_SECURITY,
NULL,
&pSDNew);
_JumpIfError(hr, error, "myGetSDFromTemplate");
}
else
{
pAclNew = (PACL)LocalAlloc(LMEM_FIXED, dwSizeAclNew);
if(!pAclNew)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
FillMemory(pAclNew, dwSizeAclNew, L' ');
if(!InitializeAcl(pAclNew, dwSizeAclNew, ACL_REVISION))
{
hr = myHLastError();
_JumpError(hr, error, "InitializeAcl");
}
for(cAce=0;cAce<OldAclSizeInfo.AceCount;cAce++)
{
if(!GetAce(pAclOld, cAce, &pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
if(GetUpgradeAceSizeAndType(
pAce,
&dwAccessMask,
&pSid))
{
BYTE acetype = ((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType;
switch(acetype)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
if(!AddAccessAllowedAce(
pAclNew,
ACL_REVISION,
dwAccessMask,
pSid))
{
hr = myHLastError();
_JumpError(hr, error, "AddAccessAllowed");
}
break;
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
if(!AddAccessDeniedAce(
pAclNew,
ACL_REVISION,
dwAccessMask,
pSid))
{
hr = myHLastError();
_JumpError(hr, error, "AddAccessAllowed");
}
break;
}
}
}
// Build a new SD based on this DACL
pSDNewDaclOnly = (PSECURITY_DESCRIPTOR)LocalAlloc(
LMEM_FIXED,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!pSDNewDaclOnly)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (!InitializeSecurityDescriptor(
pSDNewDaclOnly,
SECURITY_DESCRIPTOR_REVISION))
{
hr = myHLastError();
_JumpError(hr, error, "InitializeSecurityDescriptor");
}
if(!SetSecurityDescriptorDacl(pSDNewDaclOnly,
TRUE,
pAclNew,
FALSE))
{
hr = myHLastError();
_JumpError(hr, error, "SetSecurityDescriptorDacl");
}
hr= myGetSDFromTemplate(
WSZ_DEFAULT_CA_STD_SECURITY,
NULL,
&pSDNewSaclOnly);
_JumpIfError(hr, error, "myGetSDFromTemplate");
// merge SACL & DACL in new SD
hr = myMergeSD(
pSDNewSaclOnly,
pSDNewDaclOnly,
DACL_SECURITY_INFORMATION,
&pSDNew);
_JumpIfError(hr, error, "myMergeSD");
CSASSERT(IsValidSecurityDescriptor(pSDNew));
}
hr = Unlock();
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Unlock");
hr = CProtectedSecurityDescriptor::Set(pSDNew);
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Set");
error:
LOCAL_FREE(pSDNew);
LOCAL_FREE(pSDNewSaclOnly);
LOCAL_FREE(pSDNewDaclOnly);
LOCAL_FREE(pAclNew);
return hr;
}
DWORD CCertificateAuthoritySD::GetUpgradeAceSizeAndType(
PVOID pAce, DWORD *pdwType, PSID *ppSid)
{
DWORD dwSize = 0;
PSID pSid = NULL;
DWORD dwType = 0;
switch(((PACCESS_ALLOWED_ACE)pAce)->Header.AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
pSid = (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart);
dwSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+GetLengthSid(pSid);
switch(((PACCESS_ALLOWED_ACE)pAce)->Mask)
{
case ACTRL_CERTSRV_MANAGE:
dwType = CA_ACCESS_ADMIN | CA_ACCESS_OFFICER;
break;
default: // including ACTRL_CERTSRV_READ
dwType = CA_ACCESS_READ;
}
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
PACCESS_ALLOWED_OBJECT_ACE pObjAce = (PACCESS_ALLOWED_OBJECT_ACE)pAce;
pSid = (PSID)(((BYTE*)(&pObjAce->ObjectType))+
((pObjAce->Flags&ACE_OBJECT_TYPE_PRESENT)?
sizeof(pObjAce->ObjectType):0)+
((pObjAce->Flags&ACE_INHERITED_OBJECT_TYPE_PRESENT)?
sizeof(pObjAce->InheritedObjectType):0));
dwSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+GetLengthSid(pSid);
REFGUID rGUID = (((PACCESS_ALLOWED_OBJECT_ACE)pAce)->ObjectType);
if(IsEqualGUID(rGUID, GUID_ENROLL))
{
dwType = CA_ACCESS_ENROLL;
} else
if(IsEqualGUID(rGUID, GUID_APPRV_REQ) ||
IsEqualGUID(rGUID, GUID_REVOKE))
{
dwType = CA_ACCESS_OFFICER;
} else
{
dwType = CA_ACCESS_READ;
}
break;
// denied aces are not upgraded so ignore them
}
if(ppSid)
*ppSid = pSid;
if(pdwType)
*pdwType = dwType;
return dwSize;
}
// Returns:
// - E_INVALIDARG: invalid ACEs found,
// - S_FALSE: no admin ACE found (to avoid admins locking themselves out)
HRESULT CCertificateAuthoritySD::Validate(PSECURITY_DESCRIPTOR pSD)
{
HRESULT hr;
ACL_SIZE_INFORMATION AclInfo;
DWORD dwIndex;
PACCESS_ALLOWED_ACE pAce; // no free
PACL pDacl; // no free
bool fAdminAceFound = false;
DWORD dwKnownRights = CA_ACCESS_ADMIN |
CA_ACCESS_OFFICER |
CA_ACCESS_READ |
CA_ACCESS_ENROLL;
if(!IsValidSecurityDescriptor(pSD))
{
hr = myHLastError();
_JumpError(hr, error, "IsValidSecurityDescriptor");
}
// get acl
hr = myGetSecurityDescriptorDacl(
pSD,
&pDacl);
_JumpIfError(hr, error, "myGetDaclFromInfoSecurityDescriptor");
if(!GetAclInformation(pDacl,
&AclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
for(dwIndex = 0; dwIndex < AclInfo.AceCount; dwIndex++)
{
if(!GetAce(pDacl, dwIndex, (LPVOID*)&pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
// only access allowed/denied aces and know rights are allowed
if((ACCESS_ALLOWED_ACE_TYPE!=pAce->Header.AceType &&
ACCESS_DENIED_ACE_TYPE !=pAce->Header.AceType) ||
(~dwKnownRights & pAce->Mask))
{
return E_INVALIDARG;
}
if((CA_ACCESS_ADMIN & pAce->Mask) &&
(ACCESS_ALLOWED_ACE_TYPE==pAce->Header.AceType))
{
fAdminAceFound = true;
}
}
// no caadmin allow ace found
hr = fAdminAceFound?S_OK:CERTSRV_E_NO_CAADMIN_DEFINED;
error:
return hr;
}
HRESULT CCertificateAuthoritySD::ConvertToString(
IN PSECURITY_DESCRIPTOR pSD,
OUT LPWSTR& rpwszSD)
{
HRESULT hr = S_OK;
LPCWSTR pcwszHeader = L"\n"; // start with a new line
DWORD dwBufSize = sizeof(WCHAR)*(wcslen(pcwszHeader)+1);
ACL_SIZE_INFORMATION AclInfo;
DWORD dwIndex;
PACCESS_ALLOWED_ACE pAce; // no free
PACL pDacl; // no free
LPWSTR pwszAce; // no free
rpwszSD = NULL;
hr = Validate(pSD);
_JumpIfError(hr, error, "CCertificateAuthoritySD::Validate");
// get acl
hr = myGetSecurityDescriptorDacl(
pSD,
&pDacl);
_JumpIfError(hr, error, "myGetDaclFromInfoSecurityDescriptor");
if(!GetAclInformation(pDacl,
&AclInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation))
{
hr = myHLastError();
_JumpError(hr, error, "GetAclInformation");
}
// calculate text size
for(dwIndex = 0; dwIndex < AclInfo.AceCount; dwIndex++)
{
DWORD dwAceSize;
if(!GetAce(pDacl, dwIndex, (LPVOID*)&pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
hr = ConvertAceToString(
pAce,
&dwAceSize,
NULL);
_JumpIfError(hr, error, "ConvertAceToString");
dwBufSize += dwAceSize;
}
rpwszSD = (LPWSTR)LocalAlloc(LMEM_FIXED, dwBufSize);
_JumpIfAllocFailed(rpwszSD, error);
// build the output string
wcscpy(rpwszSD, pcwszHeader);
pwszAce = rpwszSD + wcslen(pcwszHeader);
for(dwIndex = 0; dwIndex < AclInfo.AceCount; dwIndex++)
{
DWORD dwAceSize;
if(!GetAce(pDacl, dwIndex, (LPVOID*)&pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
hr = ConvertAceToString(
pAce,
&dwAceSize,
pwszAce);
_JumpIfError(hr, error, "ConvertAceToString");
pwszAce += dwAceSize/sizeof(WCHAR);
}
error:
return hr;
}
// Returned string has the following format:
//
// [Allow|Deny]\t[Name|SID]\n
// \tRole1\n
// \tRole2\n
// ...
//
// Example:
//
// Allow Administrators
// CA Administrator
// Certificate Manager
//
// If SID cannot be converted to friendly name it is displayed
// as a string SID
//
HRESULT CCertificateAuthoritySD::ConvertAceToString(
IN PACCESS_ALLOWED_ACE pAce,
OUT OPTIONAL PDWORD pdwSize,
IN OUT OPTIONAL LPWSTR pwszSD)
{
HRESULT hr = S_OK;
DWORD dwSize = 1; // trailing '\0'
CSid sid((PSID)(&pAce->SidStart));
LPCWSTR pcwszAllow = m_pcwszResources[0];
LPCWSTR pcwszDeny = m_pcwszResources[1];
LPCWSTR pcwszPermissionType =
(ACCESS_ALLOWED_ACE_TYPE==pAce->Header.AceType)?
pcwszAllow:pcwszDeny;
LPCWSTR pcwszSid; // no free
DWORD dwRoles[] =
{
CA_ACCESS_ADMIN,
CA_ACCESS_OFFICER,
CA_ACCESS_READ,
CA_ACCESS_ENROLL,
};
// dwRoles and resources should match the roles
const LPCWSTR *pcwszRoles = &m_pcwszResources[2];
DWORD cRoles;
// asked for size and/or ace string
CSASSERT(pdwSize || pwszSD);
pcwszSid = sid.GetName();
if(!pcwszSid)
{
return E_OUTOFMEMORY;
}
dwSize = wcslen(pcwszSid);
dwSize += wcslen(pcwszPermissionType);
dwSize += 2; // '\t' between sid an permission and a '\n' after
if(pwszSD)
{
wcscat(pwszSD, pcwszPermissionType);
wcscat(pwszSD, L"\t");
wcscat(pwszSD, pcwszSid);
wcscat(pwszSD, L"\n");
}
for(cRoles=0;cRoles<ARRAYSIZE(dwRoles);cRoles++)
{
if(pAce->Mask & dwRoles[cRoles])
{
dwSize += wcslen(pcwszRoles[cRoles]) + 2; // "\tRole\n"
if(pwszSD)
{
wcscat(pwszSD, L"\t");
wcscat(pwszSD, pcwszRoles[cRoles]);
wcscat(pwszSD, L"\n");
}
}
}
dwSize *= sizeof(WCHAR);
if(pdwSize)
{
*pdwSize = dwSize;
}
return hr;
}