windows-nt/Source/XPSP1/NT/ds/security/services/ca/certmmc/officer.cpp
2020-09-26 16:20:57 +08:00

476 lines
12 KiB
C++

//+--------------------------------------------------------------------------
// File: officer.cpp
// Contents: officer rights implementation
//---------------------------------------------------------------------------
#include <stdafx.h>
#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;
cSids<pSidList->dwSidCount;
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; cAce<AclInfo.AceCount; cAce++)
{
pExistingOfficer = NULL;
if(!GetAce(pAcl, cAce, (PVOID*)&pAce))
{
hr = myHLastError();
_JumpError(hr, error, "GetAce");
}
CSASSERT(
ACCESS_ALLOWED_CALLBACK_ACE_TYPE == pAce->Header.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; cList<m_dwCountList; cList++)
{
if(EqualSid(m_List[cList]->GetSid(),
(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;cRights<m_dwCountList;cRights++)
{
dwAclSize += m_List[cRights]->GetAceSize(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;cRights<m_dwCountList;cRights++)
{
hr = m_List[cRights]->AddAce(pAcl, FALSE);
_JumpIfError(hr, error, "COfficerRights::AddAce");
}
// then add allow aces
for(cRights=0;cRights<m_dwCountList;cRights++)
{
hr = m_List[cRights]->AddAce(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<CClientPermission> 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<CClientPermission> 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;dwCount<m_dwCountList;dwCount++)
{
COfficerRights *pOR = GetAt(dwCount);
wprintf(L"Officer %s, %d clients\n", pOR->GetName(), pOR->GetCount());
for(DWORD c=0;c<pOR->GetCount();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);
}