windows-nt/Source/XPSP1/NT/admin/admt/common/commonlib/sd.cpp
2020-09-26 16:20:57 +08:00

969 lines
23 KiB
C++

/*---------------------------------------------------------------------------
File: SD.cpp
Comments: class for manipulating security descriptors
This class provides a thin wrapper around the security descriptor APIs, and
also helps us with some of our processing heuristics.
The NT APIs to read and write security descriptors for files, etc. generally
return a self-relative SD when reading, but expect an absolute SD when writing
Thus, we keep the original data of the SD as read, in self-relative form in m_relSD,
and store any changes in absolute form in m_absSD. This allows us to easily track
which parts of the SD have been modified, and to compare the before and after versions
of the SD.
As an optimization in our ACL translation, we can compare each SD to the initial
state of the last SD we processed. If it is the same, we can simply write the
result we have already calculated, instead of calculating it again.
(c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
Proprietary and confidential to Mission Critical Software, Inc.
REVISION LOG ENTRY
Revision By: Christy Boles
Revised on 01-Oct-98 15:51:41
---------------------------------------------------------------------------
*/
#include <windows.h>
#include "McsDebug.h"
#include "McsDbgU.h"
#include "SD.hpp"
TSD::TSD(
SECURITY_DESCRIPTOR * pSD, // in - pointer to self-relative security descriptor
SecuredObjectType objectType, // in - type of object this security descriptor secures
BOOL bResponsibleForDelete // in - if TRUE, this class will delete the memory for pSD
)
{
m_absSD = MakeAbsSD(pSD);
m_bOwnerChanged = FALSE;
m_bGroupChanged = FALSE;
m_bDACLChanged = FALSE;
m_bSACLChanged = FALSE;
m_bNeedToFreeSD = TRUE;
m_bNeedToFreeOwner = TRUE;
m_bNeedToFreeGroup = TRUE;
m_bNeedToFreeDacl = TRUE;
m_bNeedToFreeSacl = TRUE;
m_ObjectType = objectType;
if ( bResponsibleForDelete )
{
free(pSD);
}
}
TSD::TSD(
TSD * pSD // in - another security descriptor
)
{
MCSVERIFY(pSD);
if ( pSD )
{
m_absSD = pSD->MakeAbsSD();
m_bOwnerChanged = FALSE;
m_bGroupChanged = FALSE;
m_bDACLChanged = FALSE;
m_bSACLChanged = FALSE;
m_bNeedToFreeSD = TRUE;
m_bNeedToFreeOwner = TRUE;
m_bNeedToFreeGroup = TRUE;
m_bNeedToFreeDacl = TRUE;
m_bNeedToFreeSacl = TRUE;
m_ObjectType = pSD->GetType();
}
}
TSD::~TSD()
{
MCSVERIFY(m_absSD);
if ( m_bNeedToFreeSD )
{
if (m_absSD)
FreeAbsSD(m_absSD,FALSE);
m_absSD = NULL;
}
}
void
TSD::FreeAbsSD(
SECURITY_DESCRIPTOR * pSD, // in - pointer to security descriptor to free
BOOL bAll // in - flag whether to free all parts of the SD, or only those
// allocated by this class
)
{
PSID sid = NULL;
PACL acl = NULL;
BOOL defaulted;
BOOL present;
GetSecurityDescriptorOwner(pSD,&sid,&defaulted);
if ( sid && ( m_bNeedToFreeOwner || bAll ) )
{
free(sid);
sid = NULL;
}
GetSecurityDescriptorGroup(pSD,&sid,&defaulted);
if ( sid && ( m_bNeedToFreeGroup || bAll ) )
{
free(sid);
sid = NULL;
}
GetSecurityDescriptorDacl(pSD,&present,&acl,&defaulted);
if ( acl && (m_bNeedToFreeDacl || bAll ) )
{
free(acl);
acl = NULL;
}
GetSecurityDescriptorSacl(pSD,&present,&acl,&defaulted);
if ( acl && ( m_bNeedToFreeSacl || bAll ) )
{
free(acl);
acl = NULL;
}
free(pSD);
}
SECURITY_DESCRIPTOR * // ret- copy of the SD, in Absolute format
TSD::MakeAbsSD(
SECURITY_DESCRIPTOR * pSD // in - security descriptor to copy
) const
{
DWORD sd_size = (sizeof SECURITY_DESCRIPTOR);
DWORD dacl_size = 0;
DWORD sacl_size = 0;
DWORD owner_size = 0;
DWORD group_size = 0;
// Allocate space for the SD and its parts
SECURITY_DESCRIPTOR * absSD = (SECURITY_DESCRIPTOR *) malloc(sd_size);
if (!absSD || !pSD)
{
if (absSD)
{
free(absSD);
absSD = NULL;
}
return NULL;
}
PACL absDacl = NULL;
PACL absSacl = NULL;
PSID absOwner = NULL;
PSID absGroup = NULL;
if ( ! MakeAbsoluteSD(pSD,absSD,&sd_size,absDacl,&dacl_size,absSacl,&sacl_size
,absOwner,&owner_size,absGroup,&group_size) )
{
// DWORD rc = GetLastError();
// didn't work: increase sizes and try again
if ( sd_size > (sizeof SECURITY_DESCRIPTOR) )
{
free(absSD);
absSD = (SECURITY_DESCRIPTOR *) malloc(sd_size);
if (!absSD)
return NULL;
}
if ( dacl_size )
{
absDacl = (PACL)malloc(dacl_size);
if (!absDacl)
{
free(absSD);
absSD = NULL;
return NULL;
}
}
if ( sacl_size )
{
absSacl = (PACL)malloc(sacl_size);
if (!absSacl)
{
free(absSD);
free(absDacl);
absSD = NULL;
absDacl = NULL;
return NULL;
}
}
if ( owner_size )
{
absOwner = (PSID)malloc(owner_size);
if (!absOwner)
{
free(absSD);
free(absDacl);
free(absSacl);
absSD = NULL;
absDacl = NULL;
absSacl = NULL;
return NULL;
}
}
if ( group_size )
{
absGroup = (PSID)malloc(group_size);
if (!absGroup)
{
free(absSD);
free(absDacl);
free(absSacl);
free(absOwner);
absSD = NULL;
absDacl = NULL;
absSacl = NULL;
absOwner = NULL;
return NULL;
}
}
// try again with bigger buffers
if ( ! MakeAbsoluteSD(pSD,absSD,&sd_size,absDacl,&dacl_size,absSacl,&sacl_size
,absOwner,&owner_size,absGroup,&group_size) )
{
free(absSD);
free(absDacl);
free(absSacl);
free(absOwner);
free(absGroup);
absSD = NULL;
absDacl = NULL;
absSacl = NULL;
absOwner = NULL;
absGroup = NULL;
}
}
return absSD;
}
SECURITY_DESCRIPTOR * // ret- copy of the SD, in Absolute format
TSD::MakeAbsSD() const
{
SECURITY_DESCRIPTOR * absSD = NULL;
SECURITY_DESCRIPTOR * relSD = MakeRelSD();
if (relSD)
{
absSD = MakeAbsSD(relSD);
free(relSD);
}
return absSD;
}
SECURITY_DESCRIPTOR * // ret- copy of the SD, in self-relative form
TSD::MakeRelSD() const
{
DWORD nBytes;
SECURITY_DESCRIPTOR * relSD = NULL;
nBytes = GetSecurityDescriptorLength(m_absSD);
relSD = (SECURITY_DESCRIPTOR *)malloc(nBytes);
if (!relSD)
return NULL;
if (! MakeSelfRelativeSD(m_absSD,relSD,&nBytes) )
{
free(relSD);
relSD = NULL;
}
return relSD;
}
PSID const // ret- sid for security descriptor owner field
TSD::GetOwner() const
{
PSID ownersid = NULL;
BOOL ownerDefaulted;
GetSecurityDescriptorOwner(m_absSD,&ownersid,&ownerDefaulted);
return ownersid;
}
void
TSD::SetOwner(
PSID pNewOwner // in - new value for owner field
)
{
MCSVERIFY(IsValidSecurityDescriptor(m_absSD));
if ( IsValidSid(pNewOwner) )
{
if ( m_bNeedToFreeOwner )
{
PSID old = GetOwner();
free(old);
}
SetSecurityDescriptorOwner(m_absSD,pNewOwner,FALSE);
m_bOwnerChanged = TRUE;
m_bNeedToFreeOwner = TRUE;
}
else
{
MCSVERIFY(FALSE);
}
}
PSID const // ret- sid for security descriptor owner field
TSD::GetGroup() const
{
PSID grpsid = NULL;
BOOL grpDefaulted;
MCSVERIFY(IsValidSecurityDescriptor(m_absSD));
GetSecurityDescriptorGroup(m_absSD,&grpsid,&grpDefaulted);
return grpsid;
}
void
TSD::SetGroup(
PSID pNewGroup // in - new value for primary group field.
)
{
MCSVERIFY(IsValidSecurityDescriptor(m_absSD));
if ( IsValidSid(pNewGroup) )
{
if ( m_bNeedToFreeGroup )
{
PSID old = GetGroup();
free(old);
}
SetSecurityDescriptorGroup(m_absSD,pNewGroup,FALSE);
m_bGroupChanged = TRUE;
m_bNeedToFreeGroup = TRUE;
}
else
{
MCSVERIFY(FALSE);
}
}
PACL const // ret- pointer to DACL
TSD::GetDacl() const
{
PACL acl = NULL;
BOOL defaulted;
BOOL present;
GetSecurityDescriptorDacl(m_absSD,&present,&acl,&defaulted);
return acl;
}
void
TSD::SetDacl(
PACL pNewAcl, // in - new DACL
BOOL present // in - flag, TRUE means DACL is present.
)
{
BOOL defaulted = FALSE;
if ( IsValidAcl(pNewAcl) )
{
if ( m_bNeedToFreeDacl )
{
PACL old = GetDacl();
if ( old != pNewAcl )
{
free(old);
}
}
if (! SetSecurityDescriptorDacl(m_absSD,present,pNewAcl,defaulted) )
{
// DWORD rc = GetLastError();
}
m_bDACLChanged = TRUE;
m_bNeedToFreeDacl = TRUE;
}
else
{
MCSVERIFY(FALSE);
}
}
PACL const // ret- pointer to SACL
TSD::GetSacl() const
{
PACL acl = NULL;
BOOL defaulted;
BOOL present;
GetSecurityDescriptorSacl(m_absSD,&present,&acl,&defaulted);
return acl;
}
void
TSD::SetSacl(
PACL pNewAcl, // in - new SACL
BOOL present // in - flag, TRUE means SACL is present
)
{
BOOL defaulted = FALSE;
if ( IsValidAcl(pNewAcl) )
{
if ( m_bNeedToFreeSacl )
{
PACL old = GetSacl();
if ( old != pNewAcl )
{
free(old);
}
}
SetSecurityDescriptorSacl(m_absSD,present,pNewAcl,defaulted);
m_bSACLChanged = TRUE;
m_bNeedToFreeSacl = TRUE;
}
else
{
MCSVERIFY(FALSE);
}
}
BOOL
TSD::IsOwnerDefaulted() const
{
PSID ownersid = NULL;
BOOL ownerDefaulted = FALSE;
GetSecurityDescriptorOwner(m_absSD,&ownersid,&ownerDefaulted);
return ownerDefaulted;
}
BOOL
TSD::IsGroupDefaulted() const
{
PSID groupsid = NULL;
BOOL groupDefaulted = FALSE;
GetSecurityDescriptorGroup(m_absSD,&groupsid,&groupDefaulted);
return groupDefaulted;
}
BOOL
TSD::IsDaclDefaulted() const
{
PACL acl = NULL;
BOOL defaulted = FALSE;
BOOL present;
GetSecurityDescriptorDacl(m_absSD,&present,&acl,&defaulted);
return defaulted;
}
BOOL
TSD::IsDaclPresent() const
{
PACL acl = NULL;
BOOL defaulted;
BOOL present = FALSE;
GetSecurityDescriptorDacl(m_absSD,&present,&acl,&defaulted);
return present;
}
BOOL
TSD::IsSaclDefaulted() const
{
PACL acl = NULL;
BOOL defaulted = FALSE;
BOOL present;
GetSecurityDescriptorSacl(m_absSD,&present,&acl,&defaulted);
return defaulted;
}
BOOL
TSD::IsSaclPresent() const
{
PACL acl = NULL;
BOOL defaulted;
BOOL present = FALSE;
GetSecurityDescriptorSacl(m_absSD,&present,&acl,&defaulted);
return present;
}
BOOL
TSD::operator == (TSD & otherSD)
{
return EqualSD(&otherSD);
}
// Compares the relative SDs (relSD) for 2 TSecurityDescriptor's.
// true -> SDs are equal, false -> SDs are not equal
BOOL // ret -true iff *(this->relSD) == *(otherSD->relSD)
TSD::EqualSD(
TSD * otherSD // in -TSecurityDescriptor to compare this SD to
)
{
PSID ps1;
PSID ps2;
PACL acl1;
PACL acl2;
BOOL diffound = FALSE;
// both must be valid SD's
ps1 = NULL;
ps2 = NULL;
// if GetSecurityDescriptor* fails, EqualSid, or ACLCompare will fail
// Compare owners
ps1 = GetOwner();
ps2 = otherSD->GetOwner();
if ((ps1) && (ps2) && (! EqualSid(ps1,ps2)))
{
diffound = TRUE;
}
ps1 = NULL;
ps2 = NULL;
// Compare Groups
if ( ! diffound )
{
ps1 = GetGroup();
ps2 = otherSD->GetGroup();
if ((ps1) && (ps2) && (! EqualSid(ps1,ps2)))
{
diffound = TRUE;
}
acl1 = NULL;
acl2 = NULL;
}
// Compare DACLs
if ( ! diffound )
{
acl1 = GetDacl();
acl2 = otherSD->GetDacl();
if ((acl1) && (acl2) &&
(!ACLCompare(acl1,IsDaclPresent(),acl2,otherSD->IsDaclPresent())))
{
diffound = TRUE;
}
}
// Compare SACLs
if ( ! diffound )
{
acl1 = GetSacl();
acl2 = otherSD->GetSacl();
if ((acl1) && (acl2))
diffound = (! ACLCompare(acl1,IsSaclPresent(),acl2,otherSD->IsSaclPresent()) );
}
return ! diffound;
}
BOOL // ret- TRUE if both ACLs are the same
TSD::ACLCompare(
PACL acl1, // in -ptr to first acl to compare
BOOL present1, // in -present flag for acl1
PACL acl2, // in -ptr to second acl to compare
BOOL present2 // in -present flag for acl2
)
{
DWORD size1;
DWORD size2;
bool same = true;
if ( present1 && present2 )
{
if ( ( !acl1 && acl2 )
|| ( acl1 && ! acl2 ) )
{
same = false;
}
if ( acl1 && acl2)
{
size1 = acl1->AclSize;
size2 = acl2->AclSize;
if ( size1 != size2 )
{
same = false;
}
else
{
if ( memcmp(acl1,acl2,size1) )
{
same = false;
}
}
}
}
else
{
if ( present1 || present2 )
{
same = false;
}
}
return same;
}
int // ret- number of aces in the ACL
TSD::ACLGetNumAces(
PACL acl // in - DACL or SACL
)
{
int nAces = 0;
ACL_SIZE_INFORMATION info;
if ( acl )
{
if ( GetAclInformation(acl,&info,(sizeof info),AclSizeInformation) )
{
nAces = info.AceCount;
}
else
{
// DWORD rc=GetLastError();
}
}
return nAces;
}
DWORD // ret- number of free bytes in the ACL
TSD::ACLGetFreeBytes(
PACL acl // in - DACL or SACL
)
{
int nFree = 0;
ACL_SIZE_INFORMATION info;
if ( acl )
{
if ( GetAclInformation(acl,&info,(sizeof info),AclSizeInformation) )
{
nFree = info.AclBytesFree;
}
}
return nFree;
}
DWORD // ret- number of used bytes in the ACL
TSD::ACLGetBytesInUse(
PACL acl // in - DACL or SACL
)
{
int nBytes = 0;
ACL_SIZE_INFORMATION info;
if ( acl )
{
if ( GetAclInformation(acl,&info,(sizeof info),AclSizeInformation) )
{
nBytes = info.AclBytesInUse;
}
}
return nBytes;
}
void * // ret- pointer to ace
TSD::ACLGetAce(
PACL acl, // in - DACL or SACL
int ndx // in - index of ace to retrieve
)
{
void * ace = NULL;
if ( ndx < ACLGetNumAces(acl) )
{
if ( ! GetAce(acl,ndx,(void**)&ace) )
{
ace = NULL;
}
}
else
{
MCSASSERT(FALSE); // you specified a non-existant index
}
return ace;
}
void
TSD::ACLDeleteAce(
PACL acl, // in - DACL or SACL
int ndx // in - index of ace to delete
)
{
int nAces = ACLGetNumAces(acl);
if ( ndx < nAces )
{
DeleteAce(acl,ndx);
}
else
{
MCSASSERT(FALSE); // you specified an invalid index
}
}
// Access allowed aces are added at the beginning of the list, access denied aces are added at the end of the list
void
TSD::ACLAddAce(
PACL * ppAcl, // i/o- DACL or SACL (this function may reallocate if the acl doesn't have room
TACE * pAce, // in - ACE to add
int pos // in - position
)
{
DWORD ndx = (DWORD)pos;
DWORD rc;
PACL acl = (*ppAcl);
PACL newAcl;
DWORD numaces = ACLGetNumAces(acl);
DWORD freebytes = ACLGetFreeBytes(acl);
if (!pAce->GetBuffer())
return;
// allocate a new ACL if it doesn't already exist
if ( ! acl )
{
acl = (PACL) malloc(SD_DEFAULT_ACL_SIZE);
if (!acl)
return;
InitializeAcl(acl,SD_DEFAULT_ACL_SIZE,ACL_REVISION);
numaces = ACLGetNumAces(acl);
freebytes = ACLGetFreeBytes(acl);
}
if ( pos == -1 )
{
if ( pAce->IsAccessAllowedAce() )
{
ndx = 0;
}
else
{
ndx = MAXDWORD; // insert at end of the list
}
}
WORD currAceSize = pAce->GetSize();
if ( freebytes < currAceSize ) // we must allocate more space for the ace
{
//make a bigger acl
newAcl = (ACL*)malloc(ACLGetBytesInUse(acl) + freebytes + currAceSize);
if (!newAcl)
{
free(acl);
acl = NULL;
return;
}
memcpy(newAcl,acl,ACLGetBytesInUse(acl) + freebytes);
newAcl->AclSize +=currAceSize;
free(acl);
acl = newAcl;
}
if (! AddAce(acl,ACL_REVISION,ndx,pAce->GetBuffer(),currAceSize) )
{
rc = GetLastError();
}
(*ppAcl) = acl;
}
// creates a new ace with the specified properties
TACE::TACE(
BYTE type, // in - type of ace (ACCESS_ALLOWED_ACE_TYPE, etc.)
BYTE flags, // in - ace flags (controls inheritance, etc. use 0 for files)
DWORD mask, // in - access control mask (see constants in sd.hpp)
PSID sid // in - pointer to sid for this ace
)
{
MCSVERIFY(sid);
// allocate memory for the new ace
DWORD size = (sizeof ACCESS_ALLOWED_ACE) + GetLengthSid(sid) - (sizeof DWORD);
m_pAce = (ACCESS_ALLOWED_ACE *)malloc(size);
// Initialize the ACE
if (m_pAce)
{
m_bNeedToFree = TRUE;
m_pAce->Header.AceType = type;
m_pAce->Header.AceFlags = flags;
m_pAce->Header.AceSize = (WORD) size;
m_pAce->Mask = mask;
memcpy(&m_pAce->SidStart,sid,GetLengthSid(sid));
}
}
BYTE // ret- ace type (ACCESS_ALLOWED_ACE_TYPE, etc.)
TACE::GetType()
{
MCSVERIFY(m_pAce);
BYTE type = ACCESS_ALLOWED_ACE_TYPE;
if (m_pAce)
type = m_pAce->Header.AceType;
return type;
}
BYTE // ret- ace flags (OBJECT_INHERIT_ACE, etc.)
TACE::GetFlags()
{
MCSVERIFY(m_pAce);
BYTE flags = OBJECT_INHERIT_ACE;
if (m_pAce)
flags = m_pAce->Header.AceFlags;
return flags;
}
DWORD // ret- access control mask
TACE::GetMask()
{
MCSVERIFY(m_pAce);
DWORD mask = 0;
if (m_pAce)
mask = m_pAce->Mask;
return mask;
}
PSID // ret- sid for this ace
TACE::GetSid()
{
MCSVERIFY(m_pAce);
PSID pSid = NULL;
if (m_pAce)
pSid = &m_pAce->SidStart;
return pSid;
}
WORD // ret- size of the ace, in bytes
TACE::GetSize()
{
MCSVERIFY(m_pAce);
WORD size = 0;
if (m_pAce)
size = m_pAce->Header.AceSize;
return size;
}
BOOL
TACE::SetType(
BYTE newType // in -new type for ace
)
{
MCSVERIFY(m_pAce);
if (!m_pAce)
return FALSE;
MCSASSERT( newType=ACCESS_ALLOWED_ACE_TYPE ||
newType==ACCESS_DENIED_ACE_TYPE ||
newType==SYSTEM_AUDIT_ACE_TYPE );
m_pAce->Header.AceType = newType;
return TRUE;
}
BOOL
TACE::SetFlags(
BYTE newFlags // in - new flags for ace
)
{
MCSVERIFY(m_pAce);
if (!m_pAce)
return FALSE;
m_pAce->Header.AceFlags = newFlags;
return TRUE;
}
BOOL
TACE::SetMask(
DWORD newMask // in - new access control mask
)
{
MCSVERIFY(m_pAce);
if (!m_pAce)
return FALSE;
m_pAce->Mask = newMask;
return TRUE;
}
BOOL
TACE::SetSid(
PSID sid // in - new SID for this ace
)
{
BOOL result = FALSE;
MCSVERIFY( m_pAce );
MCSASSERT( IsValidSid(sid) );
MCSASSERT( GetLengthSid(sid) == GetLengthSid(GetSid()) );
if (!m_pAce)
return FALSE;
if ( GetLengthSid(sid) <= GetLengthSid(GetSid()) )
{
memcpy(&m_pAce->SidStart,sid,GetLengthSid(sid));
result = TRUE;
}
return result;
}
BOOL
TACE::IsAccessAllowedAce()
{
MCSVERIFY(m_pAce);
return ( GetType() == ACCESS_ALLOWED_ACE_TYPE );
}