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.
 
 
 
 
 
 

2286 lines
79 KiB

//+-------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: cacl.cxx
//
// Contents: class providing merging of an access list and an ACL
//
// Classes: CAclBuilder
//
// History: Feb-94 Created DaveMont
//
//--------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
#define NAME_NOT_FOUND L"Name Not Found"
//----------------------------------------------------------------------------
//
// This is rather an odd object. It's output is either an ACL or a list
// (array) of AccessEntries. As input it takes an (optional) ACL, and
// (optionally) multiple lists of AccessEntries. The object maintains the
// SID, user name, mask, etc. in AccountAccess object.
//
// The following 3 methods are used to input access information:
//
// SetAcl -- can only be called once
// ClearAll -- used when a call to replace all access rights is made
// AddAccessEntries -- adds a list of access entries to the object
//
// The following method generates an ACL from the information within the object:
//
// GetAcl -- allocates and generates a new ACL
//
// The following method generates a list of access entries from the information
// within the object. This list will match an ACL generated by GetAcl
//
// GetAccessEntries -- allocates and generates a list of AccessEntries
//
// The following method calculates the effective rights for a trustee based
// on the access control information within the object (but not on privileges
// the trustee may have):
//
// GetEffectiveRights-- returns the effective access rights for trustee
//
//----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Member: ctor, public
//
// Synopsis: initializes class member variables
//
// Arguments: IN - [system] - the machine where the object is
// IN - [fSaveNamesAndSids] - TRUE if this object is to be transacted
// IN - [fUsedByProviderIndependentApi] - if TRUE, SYNCHRONIZE and
// READ_CONTROL are appended to any allowed masks, thus allowing
// PROV_OBJECT_READ, ...WRITE and ...EXECUTE to be non-overlapping.
//
//----------------------------------------------------------------------------
CAcl::CAcl(LPWSTR system,
IS_CONTAINER fdir,
BOOL fSaveNamesAndSids,
BOOL fUsedByProviderIndependentApi)
:_fused_by_provider_independent_api(fUsedByProviderIndependentApi),
_aclrevision(ACL_REVISION2),
_capabilities(0),
_pcaaacl(NULL),
_pcaaaes(NULL),
_pcaaaclindex(0),
_pcaaaesindex(0),
_pcacli(NULL),
_pcaeli(NULL),
_system(system),
_fdir(fdir),
_fsave_names_and_sids(fSaveNamesAndSids)
{
}
//+---------------------------------------------------------------------------
//
// Member: dtor, public
//
// Synopsis: frees class member variables
//
//----------------------------------------------------------------------------
CAcl::~CAcl()
{
//
// have to delete the individual account accesses
//
if (_pcaaacl)
{
for (ULONG idx = 0; idx < _pcaaaclindex; idx++ )
{
delete _pcaaacl[idx];
}
AccFree(_pcaaacl);
}
if (_pcaaaes)
{
for (ULONG idx = 0; idx < _pcaaaesindex; idx++ )
{
delete _pcaaaes[idx];
}
AccFree(_pcaaaes);
}
if (_pcacli)
{
delete _pcacli;
}
if (_pcaeli)
{
delete _pcaeli;
}
}
//+---------------------------------------------------------------------------
//
// Member: new, public
//
// Synopsis:
//
//----------------------------------------------------------------------------
void * CAcl::operator new(size_t size)
{
return(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, (ULONG)size));
}
//+---------------------------------------------------------------------------
//
// Member: delete, public
//
// Synopsis:
//
//----------------------------------------------------------------------------
void CAcl::operator delete(void *p, size_t size)
{
RtlFreeHeap(RtlProcessHeap(), 0, p);
}
//+---------------------------------------------------------------------------
//
// Member: SetAcl, public
//
// Synopsis: Takes an input ACL and converts it into AccountAccess objects.
//
// Arguments: IN - [pacl] - the acl from the object
//
//----------------------------------------------------------------------------
DWORD CAcl::SetAcl(PACL pacl)
{
DWORD status;
//
// new the iterators if required
//
status = _InitIterators();
if (status != NO_ERROR)
{
return(status);
}
//
// initialize the ACL, if it exists
//
_pcacli->Init(pacl);
//
// allocate space for the ACL's array of account accesses
// (if there are any ACEs)
//
if (_pcacli->NumberEntries() > 0)
{
//
// allocate for the account accesses for the acl
//
if ( NULL != (_pcaaacl = (CAccountAccess **)AccAlloc(
(_pcacli->NumberEntries() )* sizeof(void *))))
{
//
// initialize the ACLs AccountAccesses (old AAs)
//
for (_pcacli->FirstAce(); _pcacli->MoreAces(); _pcacli->NextAce() )
{
status = _AddEntry( _pcacli,
&(_pcaaacl[_pcaaaclindex]),
&_pcaaaclindex );
if (status != NO_ERROR)
{
break;
}
}
} else
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// all done with the acl iterator now, clear it.
//
_pcacli->Init(NULL);
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: ClearAll, public
//
// Synopsis: clears the account accesses for the ACL and the access entries
// (preparatory to doing a replace all API call)
//
// Arguments: none
//
//----------------------------------------------------------------------------
DWORD CAcl::ClearAll()
{
DWORD status;
//
// new the iterators if required
//
status = _InitIterators();
if (status != NO_ERROR)
{
return(status);
}
//
// clear out the acl, if it exists
//
_pcacli->Init(NULL);
if (_pcaaacl)
{
for (ULONG idx = 0; idx < _pcaaaclindex; idx++ )
{
delete _pcaaacl[idx];
}
AccFree(_pcaaacl);
_pcaaacl = NULL;
_pcaaaclindex = 0;
}
status = ClearAccessEntries();
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: ClearAccessEntries, public
//
// Synopsis: clears the access entries AccountAccess objects. (revert)
//
// Arguments: none
//
//----------------------------------------------------------------------------
DWORD CAcl::ClearAccessEntries()
{
if (_pcaaaes)
{
for (ULONG idx = 0; idx < _pcaaaesindex; idx++ )
{
delete _pcaaaes[idx];
}
AccFree(_pcaaaes);
_pcaaaes = NULL;
_pcaaaesindex = 0;
}
return(NO_ERROR);
}
//+---------------------------------------------------------------------------
//
// Member: AddAccessEntries, public
//
// Synopsis: converts the access entries and ACL into AccountAccess objects,
//
// Arguments: IN - [ccount] - the number of access entries
// IN - [pae] - the array of access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::AddAccessEntries( ULONG ccount,
PACCESS_ENTRY pae)
{
DWORD status = NO_ERROR;
//
// new the iterators if required
//
status = _InitIterators();
if (status != NO_ERROR)
{
return(status);
}
//
// initialize the iterator thru the access entries
//
_pcaeli->Init(ccount, pae);
//
// do something if there are any access entries
//
if (_pcaeli->NumberEntries() > 0)
{
//
// if we have already processed some access entries into
// AccountAccesses, then we need to make room for more
// ie. do a re-alloc
//
if (_pcaaaes != NULL)
{
CAccountAccess **pcaaaestmp;
if (NULL != (pcaaaestmp = (CAccountAccess **)AccAlloc(
(_pcaaaesindex +
_pcaeli->NumberEntries() )* sizeof(void *)) ))
{
//
// after allocating enough space for the old and new access
// entries, move the old AccountAccesses into the new space,
//
for (ULONG aeindex = 0; aeindex < _pcaaaesindex; aeindex++)
{
status = _pcaaaes[aeindex]->Clone(&(pcaaaestmp[aeindex]));
if (status != NO_ERROR)
{
break;
}
}
//
// free the old list and its contents (AccountAccesses)
//
if (status == NO_ERROR)
{
for (ULONG idx = 0; idx < _pcaaaesindex; idx++ )
{
delete _pcaaaes[idx];
}
AccFree(_pcaaaes);
_pcaaaes = pcaaaestmp;
} else
//
// if something failed, free the new list and what ever contents
// got initialized
//
{
for (ULONG idx = 0; idx < aeindex; idx++ )
{
delete pcaaaestmp[idx];
}
AccFree(pcaaaestmp);
}
}else
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
} else
{
//
// allocate memory for the account accesses for the access entries
//
if (NULL == (_pcaaaes = (CAccountAccess **)AccAlloc(
(_pcaeli->NumberEntries() )* sizeof(void *)) ))
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (status == NO_ERROR)
{
//
// save the number of old AccountAccesses so any that are for the
// same trustee as a new access entry can be overridden (marked
// unused).
//
ULONG countold = _pcaaaesindex;
//
// create AccountAccesses for the new access entries
//
for (_pcaeli->FirstAe(); _pcaeli->MoreAes(); _pcaeli->NextAe() )
{
status = _AddEntry( _pcaeli,
&(_pcaaaes[_pcaaaesindex]),
&_pcaaaesindex );
if (status != NO_ERROR)
{
break;
}
}
}
} else
{
status = ERROR_INVALID_PARAMETER;
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: BuildAcl, public
//
// Synopsis: converts AccountAccess objects into ACEs and builds an ACL
// this is a two pass operation, the first pass calculates
// the size required for the ACL, and resolves any conficts
// between the ACL and access entries. The second pass
// builds the ACL.
//
// Arguments: OUT - [pacl] - the returned, built acl
//
//----------------------------------------------------------------------------
DWORD CAcl::BuildAcl(PACL *pacl)
{
DWORD status = NO_ERROR;
NTSTATUS ntstatus;
ULONG cacl_size, cace_count;
ULONG aceindex = 0;
ULONG newidx, oldidx;
//
// pass1 calculates the size and number of entries for an ACL or list of
// access entries based on the current contents of this class
//
status = _Pass1(&cacl_size, &cace_count, TRUE); // TRUE = build ACL
//
// now for pass2, building the ACL. The first thing to do is to
// allocate space for the ACL, then add any access entries denies
// then add any ACL denies, then add any access entries allows,
// then add any ACL allows. If any ACL denies are found after the
// first ACL allow, an error is returned. In this case the caller must
// use a replace all option to clear out the old ACL.
//
if (status == NO_ERROR)
{
*pacl = (PACL)AccAlloc( cacl_size);
if (*pacl == NULL)
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (status == NO_ERROR)
{
ntstatus = RtlCreateAcl( *pacl,
cacl_size,
ACL_REVISION2 );
if (!NT_SUCCESS(ntstatus))
{
status = RtlNtStatusToDosError(ntstatus);
}
}
if (status == NO_ERROR)
{
//
// Add any access entries denies
//
for (ULONG newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
if (_pcaaaes[newidx]->AccessMode() == DENY_ACCESS)
{
if (_pcaaaes[newidx]->MultipleTrusteeOperation() ==
TRUSTEE_IS_IMPERSONATE)
{
status = ERROR_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(ntstatus = RtlAddAccessDeniedAce(*pacl,
ACL_REVISION2,
_pcaaaes[newidx]->AccessMask(),
_pcaaaes[newidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
else
{
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaaes[newidx] );
if (status != NO_ERROR)
{
break;
}
}
//
// increment the count of added aces (so can set any
// inheritance)
//
aceindex++;
}
}
}
if (status == NO_ERROR)
{
//
// loop thru the ACL AccountAccesses until the first allow
//
for (oldidx = 0; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// add any denys found
//
if (_pcaaacl[oldidx]->AccessMode() == DENY_ACCESS)
{
if (!NT_SUCCESS(ntstatus = RtlAddAccessDeniedAce(
*pacl,
ACL_REVISION2,
_pcaaacl[oldidx]->AccessMask(),
_pcaaacl[oldidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
else
{
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaacl[oldidx] );
if (status != NO_ERROR)
{
break;
}
}
//
// increment the count of added aces (so can set any
// inheritance)
//
aceindex++;
//
// accessmode will be set to SE_AUDIT_BOTH in the case
// where some other utility has put an an ACE to
// audit both success and failure; this dll will
// insert two aces when a request is made to set
// both success and failure auditing
//
}
else if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH))
{
//
// break at the first allowed ACE
//
break;
}
} // for
}
if (status == NO_ERROR)
{
//
// loop thru the access entries AccountAccesses
//
for (newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
//
// add any grants or sets found
//
if ( (_pcaaaes[newidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
GRANT_ACCESS) )
{
if (_pcaaaes[newidx]->MultipleTrusteeOperation() ==
TRUSTEE_IS_IMPERSONATE)
{
//
// note that no mask translations additions are
// done on compound ace masks
//
if (!NT_SUCCESS(ntstatus = RtlAddCompoundAce(
*pacl,
ACL_REVISION3,
COMPOUND_ACE_IMPERSONATION,
_pcaaaes[newidx]->AccessMask(),
_pcaaaes[newidx]->ImpersonateSid(),
_pcaaaes[newidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
}
else
{
if (!NT_SUCCESS(ntstatus = RtlAddAccessAllowedAce(
*pacl,
ACL_REVISION2,
_pcaaaes[newidx]->AccessMask(),
_pcaaaes[newidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
}
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaaes[newidx] );
if (status != NO_ERROR)
{
break;
}
//
// increment the count of added aces (so can set
// any inheritance)
//
aceindex++;
}
//
// else add any audit entries
//
else if ( (_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_FAILURE) )
{
//
// allow synchronize and read control if
// used by provider independent API
//
ACCESS_MASK tmpmask;
if (_fused_by_provider_independent_api)
{
tmpmask = _pcaaaes[newidx]->AccessMask() |
SYNCHRONIZE | READ_CONTROL;
} else
{
tmpmask = _pcaaaes[newidx]->AccessMask();
}
if (!NT_SUCCESS(ntstatus = RtlAddAuditAccessAce(
*pacl,
ACL_REVISION2,
tmpmask,
_pcaaaes[newidx]->Sid(),
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_SUCCESS),
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_FAILURE))))
{
status = RtlNtStatusToDosError(ntstatus);
}
else
{
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaaes[newidx] );
}
if (status != NO_ERROR)
{
break;
}
//
// increment the count of added aces (so can set
// any inheritance)
//
aceindex++;
}
} // for
}
if (status == NO_ERROR)
{
//
// loop thru the rest of the ACLs AccountAccesses
//
for (; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// add any sets found, error if any denys found
//
if (_pcaaacl[oldidx]->AccessMode() == SET_ACCESS)
{
if (_pcaaacl[oldidx]->MultipleTrusteeOperation() ==
TRUSTEE_IS_IMPERSONATE)
{
//
// add any impersonate aces
//
if (!NT_SUCCESS(ntstatus = RtlAddCompoundAce( *pacl,
ACL_REVISION3,
COMPOUND_ACE_IMPERSONATION,
_pcaaacl[oldidx]->AccessMask(),
_pcaaacl[oldidx]->ImpersonateSid(),
_pcaaacl[oldidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
}
else
{
//
// add an access allowed ACE
//
if (!NT_SUCCESS(ntstatus = RtlAddAccessAllowedAce(
*pacl,
ACL_REVISION2,
_pcaaacl[oldidx]->AccessMask(),
_pcaaacl[oldidx]->Sid())))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
}
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaacl[oldidx] );
if (status != NO_ERROR)
{
break;
}
//
// increment the count of added aces (so can
// set any inheritance)
//
aceindex++;
}
//
// add any audit aces
//
else if ( (_pcaaacl[oldidx]->AccessMode() == SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() == SET_AUDIT_FAILURE) ||
(_pcaaacl[oldidx]->AccessMode() == SE_AUDIT_BOTH))
{
//
// allow synchronize and read control if
// used by provider independent API
// also note that if an audit both ace
// existed before, and is not being modified,
// no changes are made to the ace
//
ACCESS_MASK tmpmask;
if (_fused_by_provider_independent_api)
{
tmpmask = _pcaaacl[oldidx]->AccessMask() |
SYNCHRONIZE | READ_CONTROL;
} else
{
tmpmask = _pcaaacl[oldidx]->AccessMask();
}
//
// add an audit ace
//
if (!NT_SUCCESS(ntstatus = RtlAddAuditAccessAce(
*pacl,
ACL_REVISION2,
tmpmask,
_pcaaacl[oldidx]->Sid(),
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS),
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE))))
{
status = RtlNtStatusToDosError(ntstatus);
break;
}
else
{
//
// set the inheritance
//
status = _SetAceFlags( aceindex,
*pacl,
_pcaaacl[oldidx] );
if (status != NO_ERROR)
{
break;
}
}
//
// increment the count of added aces (so can
// set any inheritance)
//
aceindex++;
}
//
// unless the entry was marked as not used, it is
// out of order
//
else if (_pcaaacl[oldidx]->AccessMode() !=
NOT_USED_ACCESS)
{
status = ERROR_INVALID_ACL;
break;
}
} // for
}
if (status != NO_ERROR)
{
if (*pacl != NULL)
{
AccFree(*pacl);
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: BuildAccessEntries, public
//
// Synopsis: converts the ACL and access entries AccountAccesses into
// access entries. This is also a 2 pass operation, the first
// pass calculates the size and the second pass resolves conflicts,
// allocates memory and builds the access entries to return
//
// Arguments: OUT - [csize] - the returned size of the access entries
// OUT - [ccount] - the returned count of access entries
// OUT - [pae] - the returned list of access entries, this buffer
// and each trustee name in it must be freed using
// AccFree (or see below)
// IN - [fAbsolute] - If TRUE the returned access entries are in a
// single buffer and must be freed with a single
// call to AccFree
//
//----------------------------------------------------------------------------
DWORD CAcl::BuildAccessEntries(PULONG csize,
PULONG ccount,
PACCESS_ENTRY *pae,
BOOL fAbsolute)
{
DWORD status = NO_ERROR;
//
// pass1 resolve conflicts and get the size of the access entries based on
// the current contents of this class
//
status = _Pass1(csize, ccount, FALSE); // FALSE:build access entries
if (status == NO_ERROR)
{
//
// allocate space for the new entries
//
if ( NULL != (*pae = (PACCESS_ENTRY)AccAlloc(*csize) ) )
{
//
// get a pointer to where the names will be put
//
LPWSTR nameptr = (LPWSTR)((PBYTE)(*pae) + sizeof(ACCESS_ENTRY) *
*ccount);
ULONG cintcount = 0;
//
// loop thru the access entries AccountAccesses
//
for (ULONG newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
//
// add any denys found
//
if (_pcaaaes[newidx]->AccessMode() == DENY_ACCESS)
{
_BuildAccessEntry(_pcaaaes[newidx],
&nameptr,
&((*pae)[cintcount++]),
fAbsolute);
}
}
//
// loop thru the ACL AccountAccesses until the first allow
//
for (ULONG oldidx = 0; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// add any denys found
//
if (_pcaaacl[oldidx]->AccessMode() == DENY_ACCESS)
{
_BuildAccessEntry(_pcaaacl[oldidx],
&nameptr,
&((*pae)[cintcount++]),
fAbsolute);
} else if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH))
{
//
// break at the first allowed ACE
//
break;
}
}
//
// loop thru the access entries AccountAccesses
//
for (newidx = 0; newidx < _pcaaaesindex ; newidx++)
{
//
// add any grants or sets found
//
if ( (_pcaaaes[newidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
GRANT_ACCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_FAILURE) )
{
_BuildAccessEntry(_pcaaaes[newidx],
&nameptr,
&((*pae)[cintcount++]),
fAbsolute);
}
}
//
// loop thru the rest of the ACLs AccountAccesses
//
for (; oldidx < _pcaaaclindex ; oldidx++)
{
//
// add any sets found, error if any denys found
//
if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE))
{
_BuildAccessEntry(_pcaaacl[oldidx],
&nameptr,
&((*pae)[cintcount++]),
fAbsolute);
//
// unless the entry was marked as not used, it is
// out of order
//
} else if (_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH)
{
_BuildDualAuditEntries(_pcaaacl[oldidx],
&nameptr,
*pae,
&cintcount,
fAbsolute);
} else if (_pcaaacl[oldidx]->AccessMode() !=
NOT_USED_ACCESS)
{
status = ERROR_INVALID_ACL;
AccFree(*pae);
break;
}
}
ASSERT(*ccount == cintcount);
} else
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
return(status);
}
#if 0
//+---------------------------------------------------------------------------
//
// Member: GetEffectiveRights, public
//
// Synopsis: grovels the CACLs AccountAccess objects to determine the trustees
// effective access rights
//
// Arguments: IN - [ptrustee] - the name of the trustee to get effective right
// OUT - [accessmask] - effective rights for the trustee
//
//----------------------------------------------------------------------------
DWORD CAcl::GetEffectiveRights( PTRUSTEE ptrustee,
PACCESS_MASK accessmask)
{
DWORD status = NO_ERROR;
CAccountAccess caa;
//
// initialize the account access for the trustee depending on type
// of trustee
//
if (ptrustee->TrusteeForm == TRUSTEE_IS_SID)
{
status = caa.Init( (PSID)ptrustee->ptstrName,
_system,
SET_ACCESS,
0,
0,
FALSE);
}
else if (ptrustee->TrusteeForm == TRUSTEE_IS_NAME)
{
status = caa.Init( ptrustee->ptstrName,
_system,
SET_ACCESS,
0,
0,
FALSE);
}
else
{
status = ERROR_NOT_SUPPORTED;
}
if (status == NO_ERROR)
{
//
// a class to do the member check
//
CMemberCheck cmc(&caa);
//
// initialized the class
//
status = cmc.Init();
if (status == NO_ERROR)
{
ACCESS_MASK allowmask = 0, denymask = 0;
for (ULONG newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
//
// add any denys found
//
if (_pcaaaes[newidx]->AccessMode() == DENY_ACCESS)
{
status = _ComputeEffective( _pcaaaes[newidx],
&cmc,
&allowmask,
&denymask);
if (status != NO_ERROR)
{
break;
}
}
}
if (status == NO_ERROR)
{
//
// loop thru the ACL AccountAccesses until the first allow
//
for (ULONG oldidx = 0; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// add any denys found
//
if (_pcaaacl[oldidx]->AccessMode() == DENY_ACCESS)
{
status = _ComputeEffective( _pcaaacl[oldidx],
&cmc,
&allowmask,
&denymask );
if (status != NO_ERROR)
{
break;
}
}
else if (_pcaaacl[oldidx]->AccessMode() == SET_ACCESS)
{
//
// break at the first allowed ACE
//
break;
}
else if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
//
// we should not encounter any audit aces when
// we are checking for effective access rights
//
status = ERROR_INVALID_ACL;
break;
}
}
if (status == NO_ERROR)
{
//
// loop thru the access entries AccountAccesses
//
for (newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
//
// add any grants, or sets found
//
if ( (_pcaaaes[newidx]->AccessMode() ==
SET_ACCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
GRANT_ACCESS) )
{
status = _ComputeEffective( _pcaaaes[newidx],
&cmc,
&allowmask,
&denymask );
if (status != NO_ERROR)
{
break;
}
}
else if ( (_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaaes[newidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
//
// we should not encounter any audit aces when
// we are checking for effective access rights
//
status = ERROR_INVALID_ACL;
break;
}
}
if (status == NO_ERROR)
{
//
// loop thru the rest of the ACLs AccountAccesses
//
for (; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// add any sets or audits found, error if any
// denys found
//
if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_ACCESS) )
{
status = _ComputeEffective( _pcaaacl[oldidx],
&cmc,
&allowmask,
&denymask );
if (status != NO_ERROR)
{
break;
}
}
else if (_pcaaacl[oldidx]->AccessMode() !=
NOT_USED_ACCESS)
{
//
// unless the entry was marked as not used, it is
// out of order
//
status = ERROR_INVALID_ACL;
break;
}
}
}
}
}
if (status == NO_ERROR)
{
//
// set the effective rights to be the alloweds minus the denieds
// (because of required ordering)
//
*accessmask = allowmask & ~denymask;
}
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: GetAuditedRights, public
//
// Synopsis: grovels the CACLs AccountAccess objects to determine the trustees
// audited rights
//
// Arguments: IN - [ptrustee] - the name of the trustee to get effective right
// OUT - [successmask] - success audited rights for the trustee
// OUT - [failuremask] - failure audited rights for the trustee
//
//----------------------------------------------------------------------------
DWORD CAcl::GetAuditedRights(PTRUSTEE ptrustee,
PACCESS_MASK successmask,
PACCESS_MASK failuremask)
{
DWORD status;
CAccountAccess caa;
*successmask = 0;
*failuremask = 0;
//
// initialize the account access for the trustee depending on form of
// trustee
//
if (ptrustee->TrusteeForm == TRUSTEE_IS_SID)
{
status = caa.Init( (PSID)ptrustee->ptstrName,
_system,
SET_ACCESS,
0,
0,
FALSE );
}
else if (ptrustee->TrusteeForm == TRUSTEE_IS_NAME)
{
status = caa.Init( ptrustee->ptstrName,
_system,
SET_ACCESS,
0,
0,
FALSE );
}
else
{
status = ERROR_NOT_SUPPORTED;
}
if (status == NO_ERROR)
{
//
// a class to do the member check
//
CMemberCheck cmc(&caa);
//
// initialized the class
//
status = cmc.Init();
if (status == NO_ERROR)
{
//
// loop thru the access entry accesses
//
for (ULONG newidx = 0; newidx < _pcaaaesindex ; newidx++ )
{
//
// no access convered by ace with inherit only flag on
//
if (0 == (_pcaaaes[newidx]->AceFlags() & INHERIT_ONLY_ACE ) )
{
BOOL fresult;
//
// check if the trustee is a member of the account access id
//
status = cmc.IsMemberOf( _pcaaaes[newidx],
&fresult );
if (status == NO_ERROR)
{
if (fresult == TRUE)
{
//
// then decide which type to add it to
//
if ( (_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaaes[newidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
*successmask |=_pcaaaes[newidx]->AccessMask();
}
if ( (_pcaaaes[newidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaaes[newidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
*failuremask |=_pcaaaes[newidx]->AccessMask();
}
}
}
else
{
break;
}
}
}
if (status == NO_ERROR)
{
//
// loop thru the ACL AccountAccesses
//
for (ULONG oldidx = 0; oldidx < _pcaaaclindex ; oldidx++ )
{
//
// no access convered by ace with inherit only flag on
//
if (0 == (_pcaaacl[oldidx]->AceFlags() & INHERIT_ONLY_ACE ) )
{
BOOL fresult;
//
// check if the trustee is a member of the account
// access id
//
status = cmc.IsMemberOf( _pcaaacl[oldidx],
&fresult );
if (status == NO_ERROR)
{
if (fresult == TRUE)
{
//
// then decide which type to add it to
//
if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_SUCCESS) ||
(_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
*successmask |=_pcaaacl[oldidx]->AccessMask();
}
if ( (_pcaaacl[oldidx]->AccessMode() ==
SET_AUDIT_FAILURE) ||
(_pcaaacl[oldidx]->AccessMode() ==
SE_AUDIT_BOTH) )
{
*failuremask |=_pcaaacl[oldidx]->AccessMask();
}
}
}
else
{
break;
}
}
}
}
}
}
return(status);
}
#endif
//+---------------------------------------------------------------------------
//
// Member: _InitIterators, private
//
// Synopsis: resolves any conficts between the ACL and access entries,
// and calculates the size required for an ACL or access entries
// to return
//
// Arguments: none
//
//----------------------------------------------------------------------------
DWORD CAcl::_InitIterators()
{
DWORD status = NO_ERROR;
//
// new the iterators if required
//
if (_pcacli == NULL)
{
if (NULL == (_pcacli = new CAclIterator()))
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (status == NO_ERROR)
{
if (_pcaeli == NULL)
{
if (NULL == (_pcaeli = new CAesIterator()))
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _Pass1, private
//
// Synopsis: resolves any conficts between the ACL and access entries,
// and calculates the size required for an ACL or access entries
// to return
//
// Arguments: [OUT] cSize - the size required for an ACL or access entries
// [OUT] cCount - the count of ACEs or access entries
// [IN] fBuildAcl - if FALSE, calculate size for access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::_Pass1(PULONG cSize, PULONG cCount, BOOL fBuildAcl)
{
DWORD status = NO_ERROR;
BOOL useentry;
//
// initialize the size.
//
*cSize = fBuildAcl ? sizeof(ACL) : 0;
*cCount = 0;
//
// assume that we are using all the (remaining) ACL entries
// (ie. whats one more loop)
//
for (ULONG aclindex = 0; aclindex < _pcaaaclindex; aclindex++)
{
//
// don't process any entries marked not used
//
if (_pcaaacl[aclindex]->AccessMode() != NOT_USED_ACCESS)
{
status = _UseEntry( _pcaaacl[aclindex],
cSize,
cCount,
fBuildAcl );
if (status != NO_ERROR)
{
break;
}
}
}
//
// if there are any access entries, resolve any conflicts
//
for (ULONG aeindex = 0; aeindex < _pcaaaesindex; aeindex++)
{
//
// don't process any entries already marked not used.
// (perhaps from a previous pass)
//
if (_pcaaaes[aeindex]->AccessMode() != NOT_USED_ACCESS)
{
//
// first check for matching SIDs in the ACL
//
status = _CheckEntryList( _pcaaaes[aeindex],
_pcaaacl,
_pcaaaclindex,
cSize,
cCount,
fBuildAcl );
if (status != NO_ERROR)
{
break;
}
//
// if the entry is still needed (access not already provided
// by a previous entry), check the access entries list for matches
//
if (_pcaaaes[aeindex]->AccessMode() != NOT_USED_ACCESS)
{
//
// then check for matching SIDS in any previous access entries
//
status = _CheckEntryList( _pcaaaes[aeindex],
_pcaaaes,
aeindex,
cSize,
cCount,
fBuildAcl );
if (status != NO_ERROR)
{
break;
}
//
// all done checking, if we still want the entry, use it
//
if ( (_pcaaaes[aeindex]->AccessMode() != NOT_USED_ACCESS) &&
(_pcaaaes[aeindex]->AccessMode() != REVOKE_ACCESS) )
{
status = _UseEntry( _pcaaaes[aeindex],
cSize,
cCount,
fBuildAcl );
if (status != NO_ERROR)
{
break;
}
}
}
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _CheckEntryList, private
//
// Synopsis: resolves any conficts between the ACL and access entries,
// and calculates the size required for an ACL or access entries
// to return
//
// Arguments: [IN] pCAA - the Account Access class to check for matches against
// the list of account accessses
// [IN] plistCAA - the list of account accesses to search thru
// [IN] clistlength - the number of entries in the list
// [IN/OUT] cSize - the size required for an ACL or access entries
// [IN/OUT] cCount - the size required for an ACL or access entries
// [IN] fBuildAcl - if FALSE, calculate size for access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::_CheckEntryList(CAccountAccess *pCAA,
CAccountAccess **plistCAA,
ULONG clistlength,
PULONG cSize,
PULONG cCount,
BOOL fBuildAcl)
{
DWORD status = NO_ERROR;
BOOL dontuseentry = FALSE;
for (ULONG index = 0; index < clistlength; index++)
{
//
// don't process any entries already marked not used.
// (perhaps from a previous pass)
//
if (plistCAA[index]->AccessMode() != NOT_USED_ACCESS)
{
//
// check for matching ids (and matching modes, see
// accesscontrolcdd.doc for a full explaination of this)
// this impersonate stuff is specifically for DS objects,
// and the kind of ace management they do (specifically, see
// notes on DS object specific permissions, and query access
//
if ( (RtlEqualSid( pCAA->Sid(), plistCAA[index]->Sid())) &&
( ( (pCAA->AccessMode() == DENY_ACCESS) ||
(plistCAA[index]->AccessMode() == DENY_ACCESS) ) ||
( (pCAA->MultipleTrusteeOperation() != TRUSTEE_IS_IMPERSONATE) &&
(plistCAA[index]->MultipleTrusteeOperation() != TRUSTEE_IS_IMPERSONATE) ||
( (pCAA->MultipleTrusteeOperation() == TRUSTEE_IS_IMPERSONATE) &&
(plistCAA[index]->MultipleTrusteeOperation() == TRUSTEE_IS_IMPERSONATE) ))))
{
//
// do things based on the type of the new entry
//
switch (pCAA->AccessMode())
{
case GRANT_ACCESS:
case DENY_ACCESS:
//
// merge the entries
//
status = _MergeEntries(pCAA,
plistCAA[index],
cSize,
cCount,
fBuildAcl);
break;
case SET_ACCESS:
case REVOKE_ACCESS:
case SET_AUDIT_SUCCESS:
case SET_AUDIT_FAILURE:
//
// don't use the old entry (since the new one takes
// precedence)
//
status = _RemoveEntry(plistCAA[index],
cSize,
cCount,
fBuildAcl);
break;
default:
ASSERT( (pCAA->AccessMode() != GRANT_ACCESS ) ||
(pCAA->AccessMode() != DENY_ACCESS ) ||
(pCAA->AccessMode() != SET_ACCESS ) ||
(pCAA->AccessMode() != REVOKE_ACCESS ) ||
(pCAA->AccessMode() != SET_AUDIT_SUCCESS ) ||
(pCAA->AccessMode() != SET_AUDIT_FAILURE ) );
break;
}
}
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _UseEntry, private
//
// Synopsis: uses the entry for the ACL or access entries being built
//
// Arguments: [IN] pCAA - the Account Access class to use
// [IN/OUT] cSize - the size required for an ACL or access entries
// [IN/OUT] cCount - the size required for an ACL or access entries
// [IN] fBuildAcl - if FALSE, calculate size for access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::_UseEntry(CAccountAccess *pCAA,
PULONG cSize,
PULONG cCount,
BOOL fBuildAcl)
{
DWORD status = NO_ERROR;
if (fBuildAcl)
{
//
// increment the count (of aces in this case)
// and grow the size
//
(*cSize) += _GetAceSize(pCAA);
} else
{
//
// get the size of the access entry
//
ULONG centrysize;
status = _GetAccessEntrySize( pCAA,
&centrysize);
if (status == NO_ERROR)
{
(*cSize) += centrysize;
if (pCAA->AccessMode() == SE_AUDIT_BOTH)
{
//
// if it is an audit both (success and failure) ACE,
// add two access entries
//
(*cSize) += centrysize;
(*cCount)++;
}
}
}
//
// increment the count (of access entries)
//
(*cCount)++;
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _RemoveEntry, private
//
// Synopsis: removes the entry from those to be used for the ACL or access
// entries being built
//
// Arguments: [IN] pCAA - the Account Access class to not use
// [IN/OUT] cSize - the size required for an ACL or access entries
// [IN/OUT] cCount - the size required for an ACL or access entries
// [IN] fBuildAcl - if FALSE, calculate size for access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::_RemoveEntry(CAccountAccess *pCAA,
PULONG cSize,
PULONG cCount,
BOOL fBuildAcl)
{
DWORD status = NO_ERROR;
ASSERT(pCAA->AccessMode() != NOT_USED_ACCESS);
if (fBuildAcl)
{
//
// increment the count (of aces in this case)
// and grow the size
//
(*cSize) -= _GetAceSize(pCAA);
} else
{
//
// get the size of the access entry
//
ULONG centrysize;
status = _GetAccessEntrySize( pCAA,
&centrysize );
if (status == NO_ERROR)
{
(*cSize) -= centrysize;
}
}
//
// increment the count (of access entries)
//
(*cCount)--;
pCAA->SetAccessMode(NOT_USED_ACCESS);
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _MergeEntries, private
//
// Synopsis: this merge function checks two access entries with matching
// SIDs for inheritance and mask intersections. It is assumed that
// the new access entry is either DENY_ACCESS or GRANT_ACCESS,
// and the old entry is either DENY_ACCESS, GRANT_ACCESS, or SET_ACCESS
//
// Arguments: [IN] pnewCAA - the new Account Access class to merge with the
// old one
// [IN] poldCAA - the old Account Access class
// [IN/OUT] cSize - the size required for an ACL or access entries
// [IN/OUT] cCount - the size required for an ACL or access entries
// [IN] fBuildAcl - if FALSE, calculate size for access entries
//
//----------------------------------------------------------------------------
DWORD CAcl::_MergeEntries(CAccountAccess *pnewCAA,
CAccountAccess *poldCAA,
PULONG cSize,
PULONG cCount,
BOOL fBuildAcl)
{
DWORD status = NO_ERROR;
BOOL leave_old_ace = FALSE;
//
// bogus while loop for fake gotos
//
while(1)
{
//
// can't set inheritance on objects
//
if ( ( (_fdir == ACCESS_TO_UNKNOWN ) ||
(_fdir == ACCESS_TO_OBJECT ) ) &&
(0 != pnewCAA->AceFlags()) )
{
status = ERROR_INVALID_PARAMETER;
break;
} else if (_fdir == ACCESS_TO_CONTAINER )
{
//
// check for inheritance intersections
//
if (0 == (pnewCAA->AceFlags() & poldCAA->AceFlags()))
{
//
// if disjoint inheritance, the entries really don't match
//
break;
} else if (pnewCAA->AceFlags() != poldCAA->AceFlags())
{
//
// if the entries inheritance intersects in some way, return an
// error (can only set or revoke access in this case)
//
status = ERROR_INVALID_PARAMETER;
break;
}
}
//
// now to merge the masks, switch on mask intersection type, and
// then on entry types,
// NOTE that SYNCHRONIZE and READ_CONTROL are always added on the
// mask compares, however
// it is only actually applied on the SET_ACCESS ACEs, so that, for
// example, READ can be allowed, and WRITE can be denied (as opposed to
// not granted).
//
if (0 == ((pnewCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL) &
(poldCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL)))
{
//
// disjoint
//
if ( (pnewCAA->AccessMode() == poldCAA->AccessMode()) ||
( (pnewCAA->AccessMode() != DENY_ACCESS) &&
(poldCAA->AccessMode() != DENY_ACCESS) ) )
{
//
// equivalent modes
//
pnewCAA->SetAccessMask(pnewCAA->AccessMask() |
poldCAA->AccessMask());
status = _RemoveEntry(poldCAA,
cSize,
cCount,
fBuildAcl);
}
} else if ((pnewCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL) ==
(poldCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL) )
{
//
// equal
//
status = _RemoveEntry(poldCAA,
cSize,
cCount,
fBuildAcl);
} else if ( (poldCAA->AccessMask() | pnewCAA->AccessMask() |
SYNCHRONIZE | READ_CONTROL) ==
(poldCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL))
{
//
// new is subset of old
//
if ( (pnewCAA->AccessMode() == poldCAA->AccessMode()) ||
( (pnewCAA->AccessMode() != DENY_ACCESS) &&
(poldCAA->AccessMode() != DENY_ACCESS) ) )
{
//
// equivalent modes
//
pnewCAA->SetAccessMode(NOT_USED_ACCESS);
} else
{
//
// one is deny, one is allow
//
poldCAA->SetAccessMask(poldCAA->AccessMask() &
~(pnewCAA->AccessMask()));
}
} else if ( (poldCAA->AccessMask() | pnewCAA->AccessMask() |
SYNCHRONIZE | READ_CONTROL) ==
(pnewCAA->AccessMask() | SYNCHRONIZE | READ_CONTROL))
{
//
// old is subset of new
//
status = _RemoveEntry(poldCAA,
cSize,
cCount,
fBuildAcl);
} else
{
//
// overlapping
//
if ( ( (pnewCAA->AccessMode() | SYNCHRONIZE | READ_CONTROL) ==
(poldCAA->AccessMode() | SYNCHRONIZE | READ_CONTROL) ) ||
( (pnewCAA->AccessMode() != DENY_ACCESS) &&
(poldCAA->AccessMode() != DENY_ACCESS) ) )
{
//
// equivalent modes
//
pnewCAA->SetAccessMask(pnewCAA->AccessMask() |
poldCAA->AccessMask());
status = _RemoveEntry(poldCAA,
cSize,
cCount,
fBuildAcl);
} else
{
//
// one is deny, one is allow
//
poldCAA->SetAccessMask(poldCAA->AccessMask() &
~(pnewCAA->AccessMask()));
}
}
break;
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _BuildAccessEntry, private
//
// Synopsis: converts an AccountAccess into an access entry
//
// Arguments: [IN] pCAA - the AccountAccess being converted to an access entry
// [IN] nameptr - where to put the trustee name
// [OUT] pAccessEntry - access entry to be stuffed
// [IN] fAbsolute - if TRUE, trustee names are pointers
//
//+---------------------------------------------------------------------------
void CAcl::_BuildAccessEntry(CAccountAccess *pCAA,
LPWSTR *nameptr,
PACCESS_ENTRY pAccessEntry,
BOOL fAbsolute)
{
pAccessEntry->AccessMode = pCAA->AccessMode();
pAccessEntry->InheritType = (pCAA->AceFlags() & ACLBUILD_VALID_ACE_FLAGS);
pAccessEntry->AccessMask = pCAA->AccessMask();
//
// now to make the trustee, first the single one
//
if (NULL != pCAA->Name())
{
wcscpy(*nameptr, pCAA->Name());
} else
{
wcscpy(*nameptr, NAME_NOT_FOUND);
}
BuildTrusteeWithName(&(pAccessEntry->Trustee), *nameptr);
//
// return the real (simplified) trustee type
//
switch (pCAA->SidType())
{
case SidTypeUser:
pAccessEntry->Trustee.TrusteeType = TRUSTEE_IS_USER;
break;
case SidTypeGroup:
case SidTypeDomain:
case SidTypeAlias:
case SidTypeWellKnownGroup:
pAccessEntry->Trustee.TrusteeType = TRUSTEE_IS_GROUP;
break;
case SidTypeDeletedAccount:
case SidTypeInvalid:
case SidTypeUnknown:
default:
pAccessEntry->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
break;
}
//
// increment to the next trustee
//
*nameptr = (LPWSTR)((PBYTE)(*nameptr) + (wcslen(*nameptr) + 1) * sizeof(WCHAR));
//
// now if there is a multiple trustee
//
if (pCAA->MultipleTrusteeOperation() == TRUSTEE_IS_IMPERSONATE)
{
//
// make space for the impersonate trustee
//
PTRUSTEE pImpTrustee = (PTRUSTEE)*nameptr;
(*nameptr) = (LPWSTR)((PBYTE)*nameptr + sizeof(TRUSTEE));
//
// figure out the sid size
// why not make the server a name based trustee??
// answer: because it is not easier
//
PSID psid = pCAA->ImpersonateSid();
ULONG sidsize = RtlLengthSid(psid);
//
// copy the sid, and increment the buffer pointer
//
RtlCopySid(sidsize, *nameptr,psid);
//
// connect the trustee together with the sid
//
BuildTrusteeWithSid(pImpTrustee, *nameptr);
//
// move the buffer pointer past the sid
//
(*nameptr) = (LPWSTR)((PBYTE)*nameptr + sidsize);
//
// finally turn the original trustee into an impersonate trustee
// with the other one
//
BuildImpersonateTrustee(&(pAccessEntry->Trustee), pImpTrustee);
}
}
//+---------------------------------------------------------------------------
//
// Member: _BuildDualAuditEntries, private
//
// Synopsis: converts an ACEs AccountAccess for auditing both success
// and failed opens into two access entries
//
// Arguments: [IN] pCAA - the AccountAccess being converted to an access entry
// [IN] nameptr - where to put the trustee name
// [IN/OUT] pae - list of access entries to be stuffed
// [IN/OUT] ccount - index into access entry list to start stuffing
// [IN] fAbsolute - if TRUE, trustee names are pointers
//
//+---------------------------------------------------------------------------
void CAcl::_BuildDualAuditEntries(CAccountAccess *pCAA,
LPWSTR *nameptr,
PACCESS_ENTRY pae,
DWORD *ccount,
BOOL fAbsolute)
{
//
// first add an access entry for the successful open
_BuildAccessEntry(pCAA,
nameptr,
&(pae[*ccount]),
fAbsolute);
pae[(*ccount)++].AccessMode = SET_AUDIT_SUCCESS;
//
// then add an entry for the failed open
//
_BuildAccessEntry(pCAA,
nameptr,
&(pae[*ccount]),
fAbsolute);
pae[(*ccount)++].AccessMode = SET_AUDIT_FAILURE;
}
#if 0
//+---------------------------------------------------------------------------
//
// Member: _ComputeEffective, private
//
// Synopsis: computes effective rights from an AccountAccess, including
// doing a check for group membership
//
// Arguments: [IN] pCAA - the AccountAccess to test against
// [IN] cMC - the member check class
// [IN OUT] AllowedMask - the mask to add allowed accesses to
// [IN OUT] DeniedMask - the mask to add denied accesses to
//
//+---------------------------------------------------------------------------
DWORD CAcl::_ComputeEffective(CAccountAccess *pCAA,
CMemberCheck *cMC,
PACCESS_MASK AllowMask,
PACCESS_MASK DenyMask)
{
DWORD status = NO_ERROR;
//
// no access convered by ace with inherit only flag on
//
if (0 == (pCAA->AceFlags() & INHERIT_ONLY_ACE ) )
{
BOOL fresult;
//
// check of the trustee is a member of the account access id
//
status = cMC->IsMemberOf( pCAA,
&fresult );
if (status == NO_ERROR)
{
if (fresult == TRUE)
{
//
// if a denied, then add to the deny mask
//
if (pCAA->AccessMode() == DENY_ACCESS)
{
*DenyMask |= pCAA->AccessMask();
//
// if a set, then add to the allowed mask
//
} else if ( (pCAA->AccessMode() == SET_ACCESS) ||
(pCAA->AccessMode() == GRANT_ACCESS) )
{
*AllowMask |= pCAA->AccessMask();
}
}
}
}
return(status);
}
#endif
//+---------------------------------------------------------------------------
//
// Member: _SetAceFlags, private
//
// Synopsis: sets the ACE (inheritance) flag on an ACE in an ACL being
// constructed1
//
// Arguments: IN - [AceIndex] - the index of the ace
// IN/OUT - [pacl] - the acl
// IN - [pcaa] - the account access for the ace index
//
//----------------------------------------------------------------------------
DWORD CAcl::_SetAceFlags(ULONG AceIndex, PACL pacl, CAccountAccess *pcaa)
{
NTSTATUS ntstatus = STATUS_SUCCESS;
if (0 != pcaa->AceFlags())
{
//
// get the ACE and set the ace flags
//
PACE_HEADER pah;
if (NT_SUCCESS(ntstatus = RtlGetAce(pacl,
AceIndex,
(void **)&pah)))
{
pah->AceFlags |= (BYTE)(pcaa->AceFlags() & VALID_INHERIT_FLAGS);
} else
{
return(RtlNtStatusToDosError(ntstatus));
}
}
return(ERROR_SUCCESS);
}
//+---------------------------------------------------------------------------
//
// Member: _GetAceSize, private
//
// Synopsis: gets the size required for an ACE
//
// Arguments: IN - [pcaa] - returns the size required for the ACE
//
//----------------------------------------------------------------------------
ULONG CAcl::_GetAceSize(CAccountAccess *pcaa)
{
if (pcaa->AccessMode() == REVOKE_ACCESS)
{
return(0);
} else if (pcaa->MultipleTrusteeOperation() == TRUSTEE_IS_IMPERSONATE)
{
return(RtlLengthSid(pcaa->Sid()) +
sizeof(ACE_HEADER) +
sizeof(ACCESS_MASK) +
sizeof(ULONG) + // sizeof compound ace type & reserved short
RtlLengthSid(pcaa->ImpersonateSid()) );
} else
{
return(RtlLengthSid(pcaa->Sid()) +
sizeof(ACE_HEADER) +
sizeof(ACCESS_MASK));
}
}
//+---------------------------------------------------------------------------
//
// Member: _GetAccessEntrySize, private
//
// Synopsis: gets the size required for an access entry
//
// Arguments: IN - [pcaa] - the size required for an access entry
//
//----------------------------------------------------------------------------
DWORD CAcl::_GetAccessEntrySize(CAccountAccess *pcaa, PULONG cAccessEntrySize)
{
DWORD status;
LPWSTR name;
status = pcaa->LookupName(&name);
if (status == NO_ERROR)
{
*cAccessEntrySize = (name == NULL ?
(wcslen(NAME_NOT_FOUND) + 1) * sizeof(WCHAR) +
sizeof(ACCESS_ENTRY) :
(wcslen(name) + 1) * sizeof(WCHAR) +
sizeof(ACCESS_ENTRY));
if (pcaa->MultipleTrusteeOperation() == TRUSTEE_IS_IMPERSONATE)
{
(*cAccessEntrySize) += (sizeof(TRUSTEE) +
RtlLengthSid(pcaa->ImpersonateSid()));
}
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _AddEntry , private
//
// Synopsis: adds an entry (either an ACE or an access entry) to the CACL
// objects list of AccountAccess objects
//
// Arguments: IN - [ci] - the iterator class
// OUT - [pcaa] - the account access class for the entry
// OUT - [pcaaindex] the index of the entry
//
//----------------------------------------------------------------------------
DWORD CAcl::_AddEntry(CIterator *ci,
CAccountAccess **pcaa,
PULONG pcaaindex)
{
DWORD status;
//
// allocate space for the account access class
//
if (NULL != (*pcaa = new CAccountAccess()))
{
//
// initialize the account access
//
status = ci->InitAccountAccess( *pcaa,
_system,
_fdir,
_fsave_names_and_sids );
if (status == NO_ERROR)
{
(*pcaaindex)++;
}
else
{
delete *pcaa;
}
}
else
{
status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// Map ERROR_BAD_INHERITANCE_ACL to NO_ERROR. That error is returned
// when an ACE is inherit-only, so we don't want it in the ACL entry.
// We do, however, want to skip the ACE so it is good that hte
// index is not incremented.
//
//
// JINHUANG: InitAccountAccess is changed so that INHERIT_ONLY ace
// is also added to the list. So this error should never be returned
//
if (status == ERROR_BAD_INHERITANCE_ACL)
{
status = NO_ERROR;
}
return(status);
}
//+---------------------------------------------------------------------------
//
// Member: _CheckForDuplicateEntries, private
//
// Synopsis: checks for duplicate AccountAccess objects in the CACLs list of
// AccountAccess objects.
//
// Arguments: IN - [pcaa] - the list of account access objects
// IN - [curindex] - the account access just added (at the end)
// IN - [countold] - the number of account accesses in the list
//
//----------------------------------------------------------------------------
DWORD CAcl::_CheckForDuplicateEntries(CAccountAccess **pcaa,
ULONG curindex,
ULONG countold)
{
DWORD status = NO_ERROR;
//
// loop thru the existing AccountAccesses to see if the latest matches
//
for (ULONG idx = 0; idx < countold; idx++)
{
if (RtlEqualSid(pcaa[idx]->Sid(), pcaa[curindex]->Sid()))
{
pcaa[idx]->SetAccessMode(NOT_USED_ACCESS);
}
}
//
// loop thru the new AccountAccesses to see if the latest matches
// (they start at countold, which is where idx is left at after
// the last loop)
//
for (; idx < curindex; idx++)
{
if (RtlEqualSid(pcaa[idx]->Sid(), pcaa[curindex]->Sid()))
{
status =ERROR_INVALID_PARAMETER;
break;
}
}
return(status);
}