503 lines
14 KiB
C++
503 lines
14 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
||
|
//
|
||
|
// File: ace.cpp
|
||
|
//
|
||
|
// This file contains the implementation of the CAce class
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "aclpriv.h"
|
||
|
#include "sddl.h" // ConvertSidToStringSid
|
||
|
|
||
|
|
||
|
CAce::CAce(PACE_HEADER pAce):pszInheritSourceName(NULL),
|
||
|
iInheritSourceLevel(0)
|
||
|
{
|
||
|
ULONG nSidLength = 0;
|
||
|
ULONG nAceLength = SIZEOF(KNOWN_ACE) - SIZEOF(ULONG);
|
||
|
|
||
|
ZeroMemory(this, SIZEOF(CAce));
|
||
|
sidType = SidTypeInvalid;
|
||
|
|
||
|
InheritedObjectType = GUID_NULL;
|
||
|
|
||
|
if (pAce != NULL)
|
||
|
{
|
||
|
PSID psidT;
|
||
|
|
||
|
// Copy the header and mask
|
||
|
*(PACE_HEADER)this = *pAce;
|
||
|
Mask = ((PKNOWN_ACE)pAce)->Mask;
|
||
|
|
||
|
// Is this an object ACE?
|
||
|
if (IsObjectAceType(pAce))
|
||
|
{
|
||
|
GUID *pGuid;
|
||
|
|
||
|
nAceLength = SIZEOF(KNOWN_OBJECT_ACE) - SIZEOF(ULONG);
|
||
|
|
||
|
// Copy the object type guid if present
|
||
|
pGuid = RtlObjectAceObjectType(pAce);
|
||
|
if (pGuid)
|
||
|
{
|
||
|
Flags |= ACE_OBJECT_TYPE_PRESENT;
|
||
|
ObjectType = *pGuid;
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//ACE_INHERITED_OBJECT_TYPE_PRESENT is invalid without
|
||
|
//either of container inherit or object inherit flags.
|
||
|
//NTRAID#NTBUG9-287737-2001/01/23-hiteshr
|
||
|
//
|
||
|
if (pAce->AceFlags & ACE_INHERIT_ALL)
|
||
|
{
|
||
|
|
||
|
//Copy the inherit type guid if present
|
||
|
pGuid = RtlObjectAceInheritedObjectType(pAce);
|
||
|
if (pGuid)
|
||
|
{
|
||
|
Flags |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
|
||
|
InheritedObjectType = *pGuid;
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy the SID
|
||
|
psidT = GetAceSid(pAce);
|
||
|
nSidLength = GetLengthSid(psidT);
|
||
|
|
||
|
psid = (PSID)LocalAlloc(LPTR, nSidLength);
|
||
|
if (psid)
|
||
|
CopyMemory(psid, psidT, nSidLength);
|
||
|
}
|
||
|
|
||
|
AceSize = (USHORT)(nAceLength + nSidLength);
|
||
|
}
|
||
|
|
||
|
|
||
|
CAce::~CAce()
|
||
|
{
|
||
|
if (psid != NULL)
|
||
|
LocalFree(psid);
|
||
|
LocalFreeString(&pszName);
|
||
|
LocalFreeString(&pszType);
|
||
|
LocalFreeString(&pszAccessType);
|
||
|
LocalFreeString(&pszInheritType);
|
||
|
LocalFreeString(&pszInheritSourceName);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CAce::SetInheritSourceInfo(LPCTSTR psz, INT level)
|
||
|
{
|
||
|
#define MAX_BUFFER 1000
|
||
|
iInheritSourceLevel = level;
|
||
|
if(psz != NULL)
|
||
|
{
|
||
|
SetString(&pszInheritSourceName,psz);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WCHAR Buffer[MAX_BUFFER];
|
||
|
if(IsInheritedAce())
|
||
|
{
|
||
|
LoadString(::hModule, IDS_FROM_PARENT, Buffer, ARRAYSIZE(Buffer));
|
||
|
SetString(&pszInheritSourceName,Buffer);
|
||
|
iInheritSourceLevel = -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LoadString(::hModule, IDS_NOT_INHERITED, Buffer, ARRAYSIZE(Buffer));
|
||
|
SetString(&pszInheritSourceName,Buffer);
|
||
|
iInheritSourceLevel = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LPTSTR
|
||
|
CAce::LookupName(LPCTSTR pszServer, LPSECURITYINFO2 psi2)
|
||
|
{
|
||
|
if (SidTypeInvalid == sidType)
|
||
|
{
|
||
|
PUSER_LIST pUserList = NULL;
|
||
|
LPCTSTR pszN = NULL;
|
||
|
LPCTSTR pszL = NULL;
|
||
|
|
||
|
sidType = SidTypeUnknown;
|
||
|
|
||
|
if (LookupSid(psid, pszServer, psi2, &pUserList))
|
||
|
{
|
||
|
sidType = pUserList->rgUsers[0].SidType;
|
||
|
pszN = pUserList->rgUsers[0].pszName;
|
||
|
pszL = pUserList->rgUsers[0].pszLogonName;
|
||
|
}
|
||
|
|
||
|
SetName(pszN, pszL);
|
||
|
|
||
|
if (pUserList)
|
||
|
LocalFree(pUserList);
|
||
|
}
|
||
|
|
||
|
return pszName;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CAce::SetName(LPCTSTR pszN, LPCTSTR pszL)
|
||
|
{
|
||
|
LocalFreeString(&pszName);
|
||
|
if (!BuildUserDisplayName(&pszName, pszN, pszL) && psid)
|
||
|
ConvertSidToStringSid(psid, &pszName);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CAce::SetSid(PSID p, LPCTSTR pszName, LPCTSTR pszLogonName, SID_NAME_USE type)
|
||
|
{
|
||
|
ULONG nSidLength = 0;
|
||
|
ULONG nAceLength = SIZEOF(KNOWN_ACE) - SIZEOF(ULONG);
|
||
|
|
||
|
if (psid != NULL)
|
||
|
{
|
||
|
LocalFree(psid);
|
||
|
psid = NULL;
|
||
|
}
|
||
|
|
||
|
if (p != NULL)
|
||
|
{
|
||
|
nSidLength = GetLengthSid(p);
|
||
|
|
||
|
psid = (PSID)LocalAlloc(LPTR, nSidLength);
|
||
|
if (psid)
|
||
|
CopyMemory(psid, p, nSidLength);
|
||
|
}
|
||
|
|
||
|
if (Flags != 0)
|
||
|
{
|
||
|
nAceLength = SIZEOF(KNOWN_OBJECT_ACE) - SIZEOF(ULONG);
|
||
|
|
||
|
if (Flags & ACE_OBJECT_TYPE_PRESENT)
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
|
||
|
if (Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
}
|
||
|
|
||
|
AceSize = (USHORT)(nAceLength + nSidLength);
|
||
|
|
||
|
sidType = type;
|
||
|
SetName(pszName, pszLogonName);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CAce::SetString(LPTSTR *ppszDest, LPCTSTR pszSrc)
|
||
|
{
|
||
|
LocalFreeString(ppszDest);
|
||
|
if (NULL != pszSrc)
|
||
|
LocalAllocString(ppszDest, pszSrc);
|
||
|
}
|
||
|
|
||
|
|
||
|
PACE_HEADER
|
||
|
CAce::Copy() const
|
||
|
{
|
||
|
PACE_HEADER pAceCopy = (PACE_HEADER)LocalAlloc(LPTR, AceSize);
|
||
|
CopyTo(pAceCopy);
|
||
|
return pAceCopy;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CAce::CopyTo(PACE_HEADER pAceDest) const
|
||
|
{
|
||
|
if (pAceDest)
|
||
|
{
|
||
|
ULONG nAceLength = SIZEOF(KNOWN_ACE) - SIZEOF(ULONG);
|
||
|
ULONG nSidLength;
|
||
|
|
||
|
// Copy the header and mask
|
||
|
*pAceDest = *(PACE_HEADER)this;
|
||
|
((PKNOWN_ACE)pAceDest)->Mask = Mask;
|
||
|
|
||
|
// Is this an object ACE?
|
||
|
if (IsObjectAceType(this))
|
||
|
{
|
||
|
GUID *pGuid;
|
||
|
|
||
|
nAceLength = SIZEOF(KNOWN_OBJECT_ACE) - SIZEOF(ULONG);
|
||
|
|
||
|
// Copy the object flags
|
||
|
((PKNOWN_OBJECT_ACE)pAceDest)->Flags = Flags;
|
||
|
|
||
|
// Copy the object type guid if present
|
||
|
pGuid = RtlObjectAceObjectType(pAceDest);
|
||
|
if (pGuid)
|
||
|
{
|
||
|
*pGuid = ObjectType;
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
}
|
||
|
|
||
|
// Copy the inherit type guid if present
|
||
|
pGuid = RtlObjectAceInheritedObjectType(pAceDest);
|
||
|
if (pGuid)
|
||
|
{
|
||
|
*pGuid = InheritedObjectType;
|
||
|
nAceLength += SIZEOF(GUID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy the SID
|
||
|
nSidLength = GetLengthSid(psid);
|
||
|
CopyMemory(GetAceSid(pAceDest), psid, nSidLength);
|
||
|
|
||
|
// The size should already be correct, but set it here to be sure.
|
||
|
pAceDest->AceSize = (USHORT)(nAceLength + nSidLength);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
CAce::CompareType(const CAce *pAceCompare) const
|
||
|
{
|
||
|
//
|
||
|
// Determine which ACE preceeds the other in canonical ordering.
|
||
|
//
|
||
|
// Return negative if this ACE preceeds pAceCompare, positive if
|
||
|
// pAceCompare preceeds this ACE, and 0 if they are equivalent in
|
||
|
// canonical ordering.
|
||
|
//
|
||
|
BOOL b1;
|
||
|
BOOL b2;
|
||
|
|
||
|
//
|
||
|
// First check inheritance. Inherited ACEs follow non-inherited ACEs.
|
||
|
//
|
||
|
b1 = AceFlags & INHERITED_ACE;
|
||
|
b2 = pAceCompare->AceFlags & INHERITED_ACE;
|
||
|
|
||
|
if (b1 != b2)
|
||
|
{
|
||
|
// One (and only one) of the ACEs is inherited.
|
||
|
return (b1 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, Allow ACEs follow Deny ACEs.
|
||
|
// Note that allow/deny has no effect on the ordering of Audit ACEs.
|
||
|
//
|
||
|
b1 = (AceType == ACCESS_ALLOWED_ACE_TYPE ||
|
||
|
AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE);
|
||
|
b2 = (pAceCompare->AceType == ACCESS_ALLOWED_ACE_TYPE ||
|
||
|
pAceCompare->AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE);
|
||
|
|
||
|
if (b1 != b2)
|
||
|
{
|
||
|
// One of the ACEs is an Allow ACE.
|
||
|
return (b1 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, Object ACEs follow non-object ACEs.
|
||
|
//
|
||
|
b1 = (AceType >= ACCESS_MIN_MS_OBJECT_ACE_TYPE &&
|
||
|
AceType <= ACCESS_MAX_MS_OBJECT_ACE_TYPE);
|
||
|
b2 = (pAceCompare->AceType >= ACCESS_MIN_MS_OBJECT_ACE_TYPE &&
|
||
|
pAceCompare->AceType <= ACCESS_MAX_MS_OBJECT_ACE_TYPE);
|
||
|
|
||
|
if (b1 != b2)
|
||
|
{
|
||
|
// One of the ACEs is an Object ACE.
|
||
|
return (b1 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
CAce::Merge(const CAce *pAce2)
|
||
|
{
|
||
|
DWORD dwStatus;
|
||
|
DWORD dwMergeFlags = 0;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
if (pAce2 == NULL)
|
||
|
return MERGE_FAIL;
|
||
|
|
||
|
//if either of the ace is inherited and they are not from the same parent
|
||
|
if( GetInheritSourceLevel() != pAce2->GetInheritSourceLevel() )
|
||
|
return MERGE_FAIL;
|
||
|
|
||
|
//
|
||
|
// The ACEs have to be the same basic type and have the same SID or
|
||
|
// there's no hope.
|
||
|
//
|
||
|
if (!IsEqualACEType(AceType, pAce2->AceType) ||
|
||
|
!EqualSid(psid, pAce2->psid))
|
||
|
return MERGE_FAIL;
|
||
|
|
||
|
if (!IsEqualGUID(InheritedObjectType, pAce2->InheritedObjectType))
|
||
|
return MERGE_FAIL; // incompatible inherit object types
|
||
|
|
||
|
if (Flags & ACE_OBJECT_TYPE_PRESENT)
|
||
|
dwMergeFlags |= MF_OBJECT_TYPE_1_PRESENT;
|
||
|
|
||
|
if (pAce2->Flags & ACE_OBJECT_TYPE_PRESENT)
|
||
|
dwMergeFlags |= MF_OBJECT_TYPE_2_PRESENT;
|
||
|
|
||
|
if (IsEqualGUID(ObjectType, pAce2->ObjectType))
|
||
|
dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
|
||
|
|
||
|
if (IsAuditAlarmACE(AceType))
|
||
|
dwMergeFlags |= MF_AUDIT_ACE_TYPE;
|
||
|
|
||
|
dwStatus = MergeAceHelper(AceFlags,
|
||
|
Mask,
|
||
|
pAce2->AceFlags,
|
||
|
pAce2->Mask,
|
||
|
dwMergeFlags,
|
||
|
&dwResult);
|
||
|
|
||
|
switch (dwStatus)
|
||
|
{
|
||
|
case MERGE_MODIFIED_FLAGS:
|
||
|
AceFlags = (UCHAR)dwResult;
|
||
|
break;
|
||
|
|
||
|
case MERGE_MODIFIED_MASK:
|
||
|
Mask = dwResult;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return dwStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IsEqualACEType(DWORD dwType1, DWORD dwType2)
|
||
|
{
|
||
|
if (dwType1 >= ACCESS_MIN_MS_OBJECT_ACE_TYPE &&
|
||
|
dwType1 <= ACCESS_MAX_MS_OBJECT_ACE_TYPE)
|
||
|
dwType1 -= (ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE);
|
||
|
|
||
|
if (dwType2 >= ACCESS_MIN_MS_OBJECT_ACE_TYPE &&
|
||
|
dwType2 <= ACCESS_MAX_MS_OBJECT_ACE_TYPE)
|
||
|
dwType2 -= (ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE);
|
||
|
|
||
|
return (dwType1 == dwType2);
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
MergeAceHelper(DWORD dwAceFlags1,
|
||
|
DWORD dwMask1,
|
||
|
DWORD dwAceFlags2,
|
||
|
DWORD dwMask2,
|
||
|
DWORD dwMergeFlags,
|
||
|
LPDWORD pdwResult)
|
||
|
{
|
||
|
// Assumptions:
|
||
|
// The ACEs are the same basic type.
|
||
|
// The SIDs are the same for both.
|
||
|
// The Inherit object type is the same for both.
|
||
|
|
||
|
if (pdwResult == NULL)
|
||
|
return MERGE_FAIL;
|
||
|
|
||
|
*pdwResult = 0;
|
||
|
|
||
|
if (dwMergeFlags & MF_OBJECT_TYPE_EQUAL)
|
||
|
{
|
||
|
if (dwAceFlags1 == dwAceFlags2)
|
||
|
{
|
||
|
//
|
||
|
// Everything matches except maybe the mask, which
|
||
|
// can be combined here.
|
||
|
//
|
||
|
if (AllFlagsOn(dwMask1, dwMask2))
|
||
|
return MERGE_OK_1;
|
||
|
else if (AllFlagsOn(dwMask2, dwMask1))
|
||
|
return MERGE_OK_2;
|
||
|
|
||
|
*pdwResult = dwMask1 | dwMask2;
|
||
|
return MERGE_MODIFIED_MASK;
|
||
|
}
|
||
|
else if ((dwAceFlags1 & VALID_INHERIT_FLAGS) == (dwAceFlags2 & VALID_INHERIT_FLAGS) &&
|
||
|
dwMask1 == dwMask2)
|
||
|
{
|
||
|
// If 2 audit aces are identical except for the audit
|
||
|
// type (success/fail), the flags can be combined.
|
||
|
if (dwMergeFlags & MF_AUDIT_ACE_TYPE)
|
||
|
{
|
||
|
*pdwResult = dwAceFlags1 | dwAceFlags2;
|
||
|
return MERGE_MODIFIED_FLAGS;
|
||
|
}
|
||
|
}
|
||
|
else if ((dwAceFlags1 & (NO_PROPAGATE_INHERIT_ACE | INHERITED_ACE | FAILED_ACCESS_ACE_FLAG | SUCCESSFUL_ACCESS_ACE_FLAG))
|
||
|
== (dwAceFlags2 & (NO_PROPAGATE_INHERIT_ACE | INHERITED_ACE | FAILED_ACCESS_ACE_FLAG | SUCCESSFUL_ACCESS_ACE_FLAG)))
|
||
|
{
|
||
|
// The NO_PROPAGATE_INHERIT_ACE bit is the same for both
|
||
|
if (dwMask1 == dwMask2)
|
||
|
{
|
||
|
// The masks are the same, so we can combine inherit flags
|
||
|
*pdwResult = dwAceFlags1;
|
||
|
|
||
|
// INHERIT_ONLY_ACE should be turned on only if it is
|
||
|
// already on in both ACEs, otherwise leave it off.
|
||
|
if (!(dwAceFlags2 & INHERIT_ONLY_ACE))
|
||
|
*pdwResult &= ~INHERIT_ONLY_ACE;
|
||
|
|
||
|
// Combine the remaining inherit flags and return
|
||
|
*pdwResult |= dwAceFlags2 & (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||
|
return MERGE_MODIFIED_FLAGS;
|
||
|
}
|
||
|
else if (AllFlagsOn(dwMask1, dwMask2))
|
||
|
{
|
||
|
// mask1 contains mask2. If Ace1 is inherited onto all of the
|
||
|
// same things that Ace2 is, then Ace2 is redundant.
|
||
|
if ((!(dwAceFlags1 & INHERIT_ONLY_ACE) || (dwAceFlags2 & INHERIT_ONLY_ACE))
|
||
|
&& AllFlagsOn(dwAceFlags1 & ACE_INHERIT_ALL, dwAceFlags2 & ACE_INHERIT_ALL))
|
||
|
return MERGE_OK_1;
|
||
|
}
|
||
|
else if (AllFlagsOn(dwMask2, dwMask1))
|
||
|
{
|
||
|
// Same as above, reversed.
|
||
|
if ((!(dwAceFlags2 & INHERIT_ONLY_ACE) || (dwAceFlags1 & INHERIT_ONLY_ACE))
|
||
|
&& AllFlagsOn(dwAceFlags2 & ACE_INHERIT_ALL, dwAceFlags1 & ACE_INHERIT_ALL))
|
||
|
return MERGE_OK_2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (dwAceFlags1 == dwAceFlags2)
|
||
|
{
|
||
|
if (!(dwMergeFlags & MF_OBJECT_TYPE_1_PRESENT) &&
|
||
|
AllFlagsOn(dwMask1, dwMask2))
|
||
|
{
|
||
|
//
|
||
|
// The other ACE has a non-NULL object type but this ACE has no object
|
||
|
// type and a mask that includes all of the bits in the other one.
|
||
|
// I.e. This ACE implies the other ACE.
|
||
|
//
|
||
|
return MERGE_OK_1;
|
||
|
}
|
||
|
else if (!(dwMergeFlags & MF_OBJECT_TYPE_2_PRESENT) &&
|
||
|
AllFlagsOn(dwMask2, dwMask1))
|
||
|
{
|
||
|
//
|
||
|
// This ACE has a non-NULL object type but the other ACE has no object
|
||
|
// type and a mask that includes all of the bits in this one.
|
||
|
// I.e. The other ACE implies this ACE.
|
||
|
//
|
||
|
return MERGE_OK_2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return MERGE_FAIL;
|
||
|
}
|