//+-------------------------------------------------------------------------- // File: officer.cpp // Contents: officer rights implementation //--------------------------------------------------------------------------- #include #include "officer.h" #include "certsd.h" using namespace CertSrv; static const DEFAULT_USERNAME_SIZE = 256; CClientPermission::CClientPermission(BOOL fAllow, PSID pSid) : m_fAllow(fAllow), m_Sid(pSid) {} HRESULT COfficerRights::Add(PSID pSid, BOOL fAllow) { HRESULT hr = S_OK; CClientPermission* pClient = new CClientPermission(fAllow, pSid); if(!CClientPermission::IsInitialized(pClient) || !m_List.AddTail(pClient)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, ""); } error: if(S_OK!=hr) delete pClient; return hr; } HRESULT COfficerRights::Init(PACCESS_ALLOWED_CALLBACK_ACE pAce) { HRESULT hr = S_OK; // no object reuse CSASSERT(!m_pSid); CSASSERT(m_List.IsEmpty()); CSASSERT(IsValidSid((PSID)(&pAce->SidStart))); m_pSid = new CSid((PSID)(&pAce->SidStart)); if(!m_pSid) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new CSid"); } hr = AddSidList(pAce); _JumpIfError(hr, error, "COfficerRights::AddSidList"); error: if(S_OK!=hr) { Cleanup(); } return hr; } HRESULT COfficerRights::AddSidList(PACCESS_ALLOWED_CALLBACK_ACE pAce) { HRESULT hr = S_OK; PSID pSid; DWORD cSids; PSID_LIST pSidList = (PSID_LIST) (((BYTE*)&pAce->SidStart)+ GetLengthSid(&pAce->SidStart)); CSASSERT(EqualSid((PSID)&pAce->SidStart, GetSid())); for(pSid=(PSID)&pSidList->SidListStart, cSids=0; cSidsdwSidCount; cSids++, pSid = (PSID)(((BYTE*)pSid)+GetLengthSid(pSid))) { hr = Add(pSid, ACCESS_ALLOWED_CALLBACK_ACE_TYPE==pAce->Header.AceType); _JumpIfError(hr, error, "COfficerRights::Add"); } error: return hr; } COfficerRightsList::~COfficerRightsList() { Cleanup(); } HRESULT COfficerRightsList::Load(PSECURITY_DESCRIPTOR pSD) { HRESULT hr = S_OK; PACL pAcl; // no free ACL_SIZE_INFORMATION AclInfo; PACCESS_ALLOWED_CALLBACK_ACE pAce; DWORD cAce; COfficerRights *pOfficerRights = NULL; DWORD cList; COfficerRights* pExistingOfficer; CSASSERT(IsValidSecurityDescriptor(pSD)); hr = myGetSecurityDescriptorDacl(pSD, &pAcl); _JumpIfError(hr, error, "myGetSecurityDescriptorDacl"); if(!GetAclInformation(pAcl, &AclInfo, sizeof(AclInfo), AclSizeInformation)) { hr = myHLastError(); _JumpError(hr, error, "GetAclInformation"); } m_dwCountList = 0; m_List = (COfficerRights **)LocalAlloc(LMEM_FIXED, sizeof(COfficerRights*)*AclInfo.AceCount); if(!m_List) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } ZeroMemory(m_List, sizeof(COfficerRights*)*AclInfo.AceCount); for(cAce=0; cAceHeader.AceType || ACCESS_DENIED_CALLBACK_ACE_TYPE == pAce->Header.AceType); // Detect if another object already exists for this officer; if so, we // will add the client list to it instead of creating a new object // Assuming denied aces always come before allow aces, we can limit // the search to allow type if(ACCESS_ALLOWED_CALLBACK_ACE_TYPE==pAce->Header.AceType) { for(cList=0; cListGetSid(), (PSID)&pAce->SidStart)) { pExistingOfficer = m_List[cList]; break; } } } if(pExistingOfficer) { // add SID list stored in this ace to existing officer object hr = pExistingOfficer->AddSidList(pAce); _JumpIfError(hr, error, "COfficerRights::AddSidList"); } else { // create new officer object pOfficerRights = new COfficerRights; if(!pOfficerRights) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new COfficerRights"); } hr = pOfficerRights->Init(pAce); _JumpIfError(hr, error, "COfficerRights::Init"); m_List[m_dwCountList] = pOfficerRights; pOfficerRights = NULL; m_dwCountList++; } } error: if(S_OK!=hr && m_List) { if(m_List) { LocalFree(m_List); m_List = NULL; } if(pOfficerRights) { delete pOfficerRights; } } return hr; } HRESULT COfficerRightsList::Save(PSECURITY_DESCRIPTOR &rpSD) { HRESULT hr = S_OK; PSECURITY_DESCRIPTOR pSD = NULL, pSDSelfRelative = NULL; DWORD dwSelfRelativeSize = 0; PSID pSidBuiltinAdministrators = NULL; PACL pAcl = NULL; rpSD = NULL; pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, SECURITY_DESCRIPTOR_MIN_LENGTH); if (!pSD) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } #ifdef _DEBUG ZeroMemory(pSD, SECURITY_DESCRIPTOR_MIN_LENGTH); #endif if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { hr = myHLastError(); _JumpError(hr, error, "InitializeSecurityDescriptor"); } hr = GetBuiltinAdministratorsSID(&pSidBuiltinAdministrators); _JumpIfError(hr, error, "GetBuiltinAdministratorsSID"); if(!SetSecurityDescriptorOwner( pSD, pSidBuiltinAdministrators, FALSE)) { hr = myHLastError(); _JumpError(hr, error, "SetSecurityDescriptorControl"); } hr = BuildAcl(pAcl); _JumpIfError(hr, error, "BuildAcl"); if(!SetSecurityDescriptorDacl( pSD, TRUE, // DACL present pAcl, FALSE)) // DACL defaulted { hr = myHLastError(); _JumpError(hr, error, "SetSecurityDescriptorDacl"); } CSASSERT(IsValidSecurityDescriptor(pSD)); MakeSelfRelativeSD(pSD, NULL, &dwSelfRelativeSize); if(ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = myHLastError(); _JumpError(hr, error, "SetSecurityDescriptorDacl"); } pSDSelfRelative = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSelfRelativeSize); if(!pSDSelfRelative) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if(!MakeSelfRelativeSD(pSD, pSDSelfRelative, &dwSelfRelativeSize)) { hr = myHLastError(); _JumpError(hr, error, "MakeSelfRelativeSD"); } rpSD = pSDSelfRelative; error: if(pAcl) { LocalFree(pAcl); } if(pSD) { LocalFree(pSD); } if(pSidBuiltinAdministrators) { LocalFree(pSidBuiltinAdministrators); } return hr; } HRESULT COfficerRightsList::BuildAcl(PACL &rpAcl) { HRESULT hr = S_OK; DWORD dwAclSize = sizeof(ACL); DWORD cRights; PACL pAcl = NULL; rpAcl = NULL; // calculate total acl size by adding the space required // for the ACEs resulting from each COfficerRights for(cRights=0;cRightsGetAceSize(FALSE); dwAclSize += m_List[cRights]->GetAceSize(TRUE); } pAcl = (PACL)LocalAlloc(LMEM_FIXED, dwAclSize); if(!pAcl) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } #ifdef _DEBUG ZeroMemory(pAcl, dwAclSize); #endif if(!InitializeAcl(pAcl, dwAclSize, ACL_REVISION)) { hr = myHLastError(); _JumpError(hr, error, "InitializeAcl"); } // add deny aces first for(cRights=0;cRightsAddAce(pAcl, FALSE); _JumpIfError(hr, error, "COfficerRights::AddAce"); } // then add allow aces for(cRights=0;cRightsAddAce(pAcl, TRUE); _JumpIfError(hr, error, "COfficerRights::AddAce"); } CSASSERT(IsValidAcl(pAcl)); rpAcl = pAcl; error: if(S_OK!=hr) { if(pAcl) { LocalFree(pAcl); } } return hr; } DWORD COfficerRights::GetAceSize(BOOL fAllow) { DWORD dwAceSize = sizeof(ACCESS_ALLOWED_CALLBACK_ACE); dwAceSize += GetLengthSid(m_pSid->GetSid()); BOOL fFound = FALSE; TPtrListEnum CPEnum(m_List); CClientPermission *pCP; for(pCP=CPEnum.Next();pCP;pCP=CPEnum.Next()) { if(pCP->GetPermission()==fAllow) { dwAceSize += GetLengthSid(pCP->GetSid()); fFound = TRUE; } } return fFound?dwAceSize:0; } HRESULT COfficerRights::AddAce(PACL pAcl, BOOL fAllow) { HRESULT hr = S_OK; PACCESS_ALLOWED_CALLBACK_ACE pAce = NULL; DWORD dwAceSize = GetAceSize(fAllow); DWORD dwSidSize = GetLengthSid(m_pSid->GetSid()); DWORD dwClientSidSize; PSID_LIST pSidList; PSID pClientSid; TPtrListEnum CPEnum(m_List); CClientPermission *pCP; BOOL fFound = FALSE; DWORD dwSidCount = 0; if(dwAceSize) { pAce = (PACCESS_ALLOWED_CALLBACK_ACE) LocalAlloc(LMEM_FIXED, dwAceSize); if(!pAce) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } #ifdef _DEBUG ZeroMemory(pAce, dwAceSize); #endif pAce->Header.AceType = fAllow?ACCESS_ALLOWED_CALLBACK_ACE_TYPE: ACCESS_DENIED_CALLBACK_ACE_TYPE; pAce->Header.AceFlags= 0; pAce->Header.AceSize = (USHORT)dwAceSize; pAce->Mask = DELETE; CopySid(dwSidSize, (PSID)&pAce->SidStart, m_pSid->GetSid()); pSidList = (PSID_LIST)(((BYTE*)&pAce->SidStart)+dwSidSize); pSidList->dwSidCount = m_List.GetCount(); pClientSid = (PSID)&pSidList->SidListStart; for(pCP=CPEnum.Next(); pCP; pCP=CPEnum.Next()) { if(pCP->GetPermission()==fAllow) { dwClientSidSize = GetLengthSid(pCP->GetSid()); CopySid(dwClientSidSize, pClientSid, pCP->GetSid()); pClientSid = (((BYTE*)pClientSid)+dwClientSidSize); fFound = TRUE; dwSidCount++; } } pSidList->dwSidCount = dwSidCount; CSASSERT(pClientSid==((BYTE*)pAce)+dwAceSize); if(fFound) { if(!::AddAce( pAcl, ACL_REVISION, MAXDWORD, pAce, dwAceSize)) { hr = myHLastError(); _JumpError(hr, error, "AddAce"); } } } error: if(pAce) { LocalFree(pAce); } return hr; } void COfficerRightsList::Dump() { DBGPRINT((DBG_SS_INFO, "Officers: %d\n", m_dwCountList)); wprintf(L"Officers: %d\n", m_dwCountList); for(DWORD dwCount=0;dwCountGetName(), pOR->GetCount()); for(DWORD c=0;cGetCount();c++) { CClientPermission *pCli = pOR->GetAt(c); wprintf(L"\tClient %s, %s\n", pCli->GetName(), pCli->GetPermission()?L"allow":L"deny"); } } } // Searches the list for an object with this SID; if found returns // object index, if not found, returns DWORD_MAX DWORD COfficerRights::Find(PSID pSid) { CClientPermission perm(TRUE, pSid); return m_List.FindIndex(perm); }