476 lines
12 KiB
C++
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);
|
||
|
}
|