Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

916 lines
23 KiB

/*---------------------------------------------------------------------------
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();
}
}
//
// This constructor allows for construction of an empty security descriptor. This is useful
// if one wishes to create a security descriptor for an object that does not currently have
// one such as a newly created share with default permissions.
//
TSD::TSD(
SecuredObjectType objectType // in - type of object this security descriptor secures
)
{
m_absSD = (SECURITY_DESCRIPTOR*) malloc(sizeof(SECURITY_DESCRIPTOR));
if (m_absSD)
{
InitializeSecurityDescriptor(m_absSD, SECURITY_DESCRIPTOR_REVISION);
}
m_bOwnerChanged = FALSE;
m_bGroupChanged = FALSE;
m_bDACLChanged = FALSE;
m_bSACLChanged = FALSE;
m_bNeedToFreeSD = TRUE;
m_bNeedToFreeOwner = FALSE;
m_bNeedToFreeGroup = FALSE;
m_bNeedToFreeDacl = FALSE;
m_bNeedToFreeSacl = FALSE;
m_ObjectType = objectType;
}
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;
}
BOOL
TSD::SetDacl(
PACL pNewAcl, // in - new DACL
BOOL present // in - flag, TRUE means DACL is present.
)
{
BOOL defaulted = FALSE;
BOOL success = TRUE;
if ( IsValidAcl(pNewAcl) )
{
if ( m_bNeedToFreeDacl )
{
PACL old = GetDacl();
if ( old != pNewAcl )
{
free(old);
}
}
if (! SetSecurityDescriptorDacl(m_absSD,present,pNewAcl,defaulted) )
{
// DWORD rc = GetLastError();
success = FALSE;
}
m_bDACLChanged = TRUE;
m_bNeedToFreeDacl = TRUE;
}
else
{
MCSVERIFY(FALSE);
success = FALSE;
}
return success;
}
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;
}
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
// Note: ppAcl and pAce should be of the same revision level, otherwise AddAce will fail
// Most usage of ACLAddAce includes two situations:
// 1) pAce is from ppAcl or a copy of ace from ppAcl
// 2) ppAcl is NULL and pAce is ACCESS_ALLOWED_ACE_TYPE
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 = NULL;
BOOL bSuccess = TRUE; // indicates whether the ACE has been added into the ACL
BOOL bOwnAcl = FALSE; // indicates whether the passed ACL is NULL so that we have to create it
DWORD numaces = ACLGetNumAces(acl);
DWORD freebytes = ACLGetFreeBytes(acl);
// allocate a new ACL if it doesn't already exist
if ( ! acl )
{
bOwnAcl = TRUE;
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
{
// if acl is created by us, we need to free it first
if (bOwnAcl)
{
free(acl);
acl = NULL;
}
// make a bigger acl
newAcl = (ACL*)malloc(ACLGetBytesInUse(acl) + freebytes + currAceSize);
if (!newAcl)
{
bSuccess = FALSE;
}
else
{
memcpy(newAcl,acl,ACLGetBytesInUse(acl) + freebytes);
newAcl->AclSize +=currAceSize;
acl = newAcl;
}
}
if (bSuccess)
{
if (!pAce->GetBuffer())
{
bSuccess = FALSE;
}
}
if (bSuccess)
{
if (! AddAce(acl,acl->AclRevision,ndx,pAce->GetBuffer(),currAceSize) )
{
bSuccess = FALSE;
}
}
if (!bSuccess)
{
if (newAcl)
free(newAcl);
else if (bOwnAcl) // if acl is created by us, we need to free it
// note: we only need to do this when newAcl is NULL
free(acl);
acl = NULL;
}
(*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;
}
DWORD
TACE::SetSid(
PSID sid // in - new SID for this ace
)
{
DWORD result = SET_SID_NOTLARGEENOUGH;
MCSVERIFY( m_pAce );
MCSASSERT( IsValidSid(sid) );
if (!m_pAce)
return SET_SID_FAILED;
if ( GetLengthSid(sid) <= GetLengthSid(GetSid()) )
{
memcpy(&m_pAce->SidStart,sid,GetLengthSid(sid));
result = SET_SID_SUCCEEDED;
}
return result;
}
BOOL
TACE::IsAccessAllowedAce()
{
MCSVERIFY(m_pAce);
return ( GetType() == ACCESS_ALLOWED_ACE_TYPE );
}