//+-------------------------------------------------------------------------- // File: casd.cpp // Contents: CCertificateAuthoritySD implementation //--------------------------------------------------------------------------- #include #include #include #include #include #include // // 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_ENROLL), NULL, &pCrtAce->SidStart)) { return myHLastError(); } } else { if(!AddAccessDeniedObjectAce( pAcl, ACL_REVISION_DS, NO_INHERITANCE, ACTRL_DS_CONTROL_ACCESS, const_cast(&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(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;cAceHeader.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;cRolesMask & 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; }