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.
921 lines
30 KiB
921 lines
30 KiB
//+-------------------------------------------------------------------
|
|
//
|
|
// File: daclwrap.cxx
|
|
//
|
|
// Contents: class encapsulating file security.
|
|
//
|
|
// Classes: CDaclWrap
|
|
//
|
|
// History: Nov-93 Created DaveMont
|
|
// Oct-96 Modified BrunoSc
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include "pch.h"
|
|
#include "t2.hxx"
|
|
#include "daclwrap.hxx"
|
|
#include "caclsmsg.h"
|
|
ULONG printmessage (FILE* fp, DWORD messageID, ...);
|
|
|
|
|
|
#if DBG
|
|
extern ULONG Debug;
|
|
#endif
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap::CDaclWrap, public
|
|
//
|
|
// Synopsis: initialize data members, constructor will not throw
|
|
//
|
|
// Arguments: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CDaclWrap::CDaclWrap()
|
|
: _ccaa(0)
|
|
{
|
|
_powner = NULL;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: Dtor, public
|
|
//
|
|
// Synopsis: cleanup allocated data
|
|
//
|
|
// Arguments: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CDaclWrap::~CDaclWrap()
|
|
{
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
delete _aaa[j].pcaa;
|
|
|
|
if (_powner) FreeSid( _powner );
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap::SetAccess, public
|
|
//
|
|
// Synopsis: caches data for a new ACE
|
|
//
|
|
// Arguments: IN [option] - rePlace, Revoke, Grant, Deny
|
|
// IN [Name] - principal (username)
|
|
// IN [System] - server/machine where Name is defined
|
|
// IN [access] - access mode (Read Change None All)
|
|
// IN [dirmask] - access mode for directory (same as access)
|
|
// IN [filespec] - if TRUE, no ACE for files will be written
|
|
// (for directories only)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::SetAccess(ULONG option, LPWSTR Name, LPWSTR System, ULONG access, ULONG dirmask, BOOL filespec)
|
|
{
|
|
ULONG ret;
|
|
|
|
// static number of ACCESSes can be set at one time
|
|
|
|
if (_ccaa >= CMAXACES)
|
|
return(ERROR_BUFFER_OVERFLOW);
|
|
|
|
// allocate a new account access class
|
|
|
|
if (NULL == (_aaa[_ccaa].pcaa = new CAccountAccess(Name, System)))
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
_aaa[_ccaa].option = option;
|
|
|
|
SID *psid;
|
|
|
|
if (ERROR_SUCCESS == ( ret = _aaa[_ccaa].pcaa->Init(access, dirmask, filespec))) // reads file security
|
|
{
|
|
// get the sid to make sure the username is valid
|
|
|
|
if (ERROR_SUCCESS == ( ret =_aaa[_ccaa].pcaa->Sid(&psid)))
|
|
{
|
|
// loop thru the existing sids, making sure the new one is not a duplicate
|
|
|
|
SID *poldsid;
|
|
for (ULONG check = 0;check < _ccaa ; check++)
|
|
{
|
|
if (ERROR_SUCCESS == ( ret =_aaa[check].pcaa->Sid(&poldsid)))
|
|
{
|
|
if (EqualSid(psid,poldsid))
|
|
{
|
|
VERBOSE((stderr, L"SetAccess found matching new sids\n"))
|
|
//NTRAID#NTBUG9-552419-2002/03/20-hiteshr
|
|
delete _aaa[_ccaa].pcaa;
|
|
return(ERROR_BAD_ARGUMENTS);
|
|
}
|
|
}
|
|
}
|
|
_ccaa++;
|
|
}
|
|
else
|
|
{
|
|
//NTRAID#NTBUG9-552419-2002/03/20-hiteshr
|
|
delete _aaa[_ccaa].pcaa;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//NTRAID#NTBUG9-552419-2002/03/20-hiteshr
|
|
delete _aaa[_ccaa].pcaa;
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:BuildAcl, public
|
|
//
|
|
// Synopsis: merges cached new aces with the input ACL
|
|
//
|
|
// Arguments: OUT [pnewdacl] - Address of new ACL to build
|
|
// IN [poldacl] - (OPTIONAL) old ACL that is to be merged
|
|
// IN [revision] - ACL revision
|
|
// IN [fdir] - True = directory
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::BuildAcl(ACL **pnewdacl, ACL *poldacl, WCHAR revision, BOOL fdir)
|
|
{
|
|
ULONG ret, caclsize;
|
|
|
|
// get the size of the new ACL we are going to create
|
|
|
|
if (ERROR_SUCCESS == (ret = _GetNewAclSize(&caclsize, poldacl, fdir)))
|
|
{
|
|
// allocate the new ACL
|
|
|
|
if (ERROR_SUCCESS == (ret = _AllocateNewAcl(pnewdacl, caclsize, revision)))
|
|
{
|
|
// and fill it up
|
|
|
|
if (ERROR_SUCCESS != (ret = _FillNewAcl(*pnewdacl, poldacl, fdir)))
|
|
{
|
|
// free the buffer if we failed
|
|
|
|
LocalFree(*pnewdacl);
|
|
}
|
|
|
|
}
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:_GetNewAclSize, private
|
|
//
|
|
// Synopsis: returns the size need to merge the new ACEs with the old ACL,
|
|
// this is an ugly algorithm:
|
|
// (with integration of different rights for directory and files
|
|
// much more uglier!! BSC )
|
|
//
|
|
// legend: a combined ACE is an ACE where the CONTAINER_INHERIT_ACE and the
|
|
// OBJECT_INHERIT_ACE Flag in the ACE header is set.
|
|
//
|
|
//if (old aces exist)
|
|
// for (new aces)
|
|
// if (new ace option == GRANT)
|
|
// for (old aces)
|
|
// if (new ace SID == old ace SID)
|
|
// do inheritance check
|
|
// found = true
|
|
// if (fdir) && (combined ACE)
|
|
// fDirEntryFound = TRUE
|
|
// if (old ace type == ALLOWED)
|
|
// new ace mask |= old ace mask
|
|
// old ace mask = 0
|
|
// else
|
|
// new ace mask &= ~old ace mask
|
|
// old ace mask = 0
|
|
// else
|
|
// if (old ace type == ALLOWED)
|
|
// old ace mask |= new ace mask
|
|
// else
|
|
// old ace mask &= ~new ace mask
|
|
// if (!found)
|
|
// if (fdir)
|
|
// add 2 times size of new ace
|
|
// else
|
|
// add size of new ace
|
|
// else
|
|
// if (fDirEntryFound)
|
|
// add size of new ace
|
|
// else
|
|
// new ace mask = 0
|
|
// else
|
|
// if (fdir)
|
|
// add 2 times the size of new ace
|
|
// else
|
|
// add size of new ace
|
|
//
|
|
// for (old aces)
|
|
// for (new aces)
|
|
// if (new ace option == DENY, REPLACE, REVOKE)
|
|
// if (new ace SID == old ace SID)
|
|
// found = true
|
|
// if (fdir) && (combined ACE)
|
|
// bDirEntryFound = TRUE
|
|
// break
|
|
// if (!found)
|
|
// if (fdir)
|
|
// add 2 times the size of old ace
|
|
// else
|
|
// add size of old ace
|
|
// else
|
|
// old ace mask = 0
|
|
// if (bDirEntryFound)
|
|
// add size of old ace
|
|
//else
|
|
// for (new aces)
|
|
// if (fdir)
|
|
// add 2 times the size of new ace
|
|
// else
|
|
// add size of new ace
|
|
//
|
|
//
|
|
// Arguments: OUT [caclsize] - returns size
|
|
// IN [poldacl] - (OPTIONAL) old ACL that is to be merged
|
|
// IN [fdir] - True = directory
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::_GetNewAclSize(ULONG *caclsize, ACL *poldacl, BOOL fdir)
|
|
{
|
|
ULONG ret;
|
|
BOOL bDirEntryFound = FALSE;
|
|
|
|
// the size for the ACL header
|
|
|
|
*caclsize = sizeof(ACL);
|
|
|
|
// initialize the access requests
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
_aaa[j].pcaa->ReInit();
|
|
|
|
// if we are merging, calculate the merge size
|
|
|
|
if (poldacl)
|
|
{
|
|
// first the grant options
|
|
|
|
for (j = 0; j < _ccaa; j++)
|
|
{
|
|
SID *psid;
|
|
if (OPTION_GRANT == _aaa[j].option)
|
|
{
|
|
BOOL ffound = FALSE;
|
|
ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
|
|
|
|
for (ULONG cace = 0; cace < poldacl->AceCount;
|
|
cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (EqualSid(psid,
|
|
(SID *)&((ACCESS_ALLOWED_ACE *)pah)->SidStart) )
|
|
{
|
|
// if old and new types are the same, just and with the old
|
|
|
|
if (fdir && (pah->AceType == _aaa[j].pcaa->AceType()))
|
|
{
|
|
// make sure that we can handle the inheritance
|
|
_aaa[j].pcaa->AddInheritance(pah->AceFlags);
|
|
|
|
ffound = TRUE;
|
|
} else if (pah->AceType == _aaa[j].pcaa->AceType())
|
|
{
|
|
ffound = TRUE;
|
|
}
|
|
|
|
// if the ACE is a 'combined' entry, it has to be
|
|
// broken into two entries: one for the directory itself,
|
|
// one for the file inheritance. But merge the old settings
|
|
// with the new ones!
|
|
if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE) && (pah->AceFlags & OBJECT_INHERIT_ACE))
|
|
{ bDirEntryFound = TRUE;
|
|
// die alte ACE wird gelöscht. -> vorher mit neuen mischen
|
|
if (ACCESS_ALLOWED_ACE_TYPE == pah->AceType)
|
|
{ _aaa[j].pcaa->Init( _aaa[j].pcaa->AccessMask() | (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
|
|
_aaa[j].pcaa->DirAccessMask() | (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
|
|
_aaa[j].pcaa->FileSpecified()
|
|
);
|
|
// and do not copy the old entry
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
|
|
}
|
|
else if (ACCESS_DENIED_ACE_TYPE == pah->AceType)
|
|
{ _aaa[j].pcaa->Init( _aaa[j].pcaa->AccessMask() & ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
|
|
_aaa[j].pcaa->DirAccessMask() & ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
|
|
_aaa[j].pcaa->FileSpecified()
|
|
);
|
|
//_aaa[j].pcaa->AccessMask() &= ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask;
|
|
// and do not copy the old entry
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
|
|
} else
|
|
{
|
|
VERBOSE((stderr, L"_GetNewAclSize found an ace that was not allowed or denied\n"))
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
else
|
|
{ if (ACCESS_ALLOWED_ACE_TYPE == pah->AceType)
|
|
{ if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE))
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask |= _aaa[j].pcaa->DirAccessMask();
|
|
else
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask |= _aaa[j].pcaa->AccessMask();
|
|
} else if (ACCESS_DENIED_ACE_TYPE == pah->AceType)
|
|
{ if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE))
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask &= ~_aaa[j].pcaa->DirAccessMask();
|
|
else
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask &= ~_aaa[j].pcaa->AccessMask();
|
|
} else
|
|
{
|
|
VERBOSE((stderr, L"_GetNewAclSize found an ace that was not allowed or denied\n"))
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
return(ret);
|
|
}
|
|
}
|
|
if (!ffound)
|
|
{
|
|
// bugbug allowed/denied sizes currently the same
|
|
|
|
*caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
// no old entry could be found. Therefore add two entries
|
|
// as described above.
|
|
if (fdir)
|
|
{ *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
}
|
|
SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
|
|
} else
|
|
{
|
|
if (fdir && (ERROR_SUCCESS != (ret = _aaa[j].pcaa->TestInheritance())))
|
|
{ // if a 'combined' entry was found, a new one has to be added.
|
|
// So adjust the size of the ACL for one entry.
|
|
if (bDirEntryFound)
|
|
{ *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
// if not needed, beceause of former 'combined' ACE,
|
|
// the new ACE(s) had been modified and therefore is not being
|
|
// copied.
|
|
if (!bDirEntryFound) _aaa[j].pcaa->ClearAccessMask();
|
|
}
|
|
} else if ( (OPTION_REPLACE == _aaa[j].option) ||
|
|
(OPTION_DENY == _aaa[j].option) )
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
// bugbug allowed/denied sizes currently the same
|
|
|
|
*caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
|
|
if (fdir)
|
|
{ *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
}
|
|
SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
|
|
} else
|
|
return(ret);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// now for the deny, replace & revoke options
|
|
ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
|
|
SID *psid;
|
|
|
|
// loop thru the old ACL
|
|
for (ULONG cace = 0; cace < poldacl->AceCount;
|
|
cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
|
|
{
|
|
BOOL ffound = FALSE;
|
|
bDirEntryFound = FALSE;
|
|
ULONG pos;
|
|
|
|
// and thru the new ACEs looking for matching SIDs
|
|
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
{
|
|
if ( (_aaa[j].option & OPTION_DENY ) ||
|
|
(_aaa[j].option & OPTION_REPLACE ) ||
|
|
(_aaa[j].option & OPTION_REVOKE ) )
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (EqualSid(psid,
|
|
(SID *)&((ACCESS_ALLOWED_ACE *)
|
|
pah)->SidStart) )
|
|
{
|
|
ffound = TRUE;
|
|
pos = j;
|
|
if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE) && (pah->AceFlags & OBJECT_INHERIT_ACE))
|
|
{ // a 'combined' entry found. Take care that the old entry
|
|
// don't get copied.
|
|
bDirEntryFound = TRUE;
|
|
}
|
|
}
|
|
} else
|
|
return(ret);
|
|
}
|
|
}
|
|
if (!ffound)
|
|
{
|
|
// if we did not find a match, add the size of the old ACE
|
|
*caclsize += ((ACE_HEADER *)pah)->AceSize;
|
|
if (fdir)
|
|
{
|
|
*caclsize += ((ACE_HEADER *)pah)->AceSize;
|
|
}
|
|
SIZE((stderr, L"adding on size of an old ACE (to the new ACL) = %d\n",*caclsize))
|
|
}
|
|
else
|
|
{
|
|
(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
|
|
// if 'combined' entry found
|
|
if (bDirEntryFound)
|
|
{ *caclsize += ((ACE_HEADER *)pah)->AceSize;
|
|
}
|
|
}
|
|
}
|
|
SIZE((stderr, L"final size for new ACL = %d\n",*caclsize))
|
|
}
|
|
else
|
|
{
|
|
// no old ACL, just add up the sizes of the new aces
|
|
|
|
for (j = 0; j < _ccaa; j++)
|
|
{
|
|
// need to know the size of the sid
|
|
|
|
SID *psid;
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
// bugbug allowed/denied sizes currently the same
|
|
|
|
*caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
// if directory, one entry for the directory itself, one for
|
|
// file inheritence
|
|
if (fdir)
|
|
{ *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
}
|
|
|
|
SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
|
|
} else
|
|
{
|
|
return(ret);
|
|
}
|
|
}
|
|
SIZE((stderr, L"final size for new ACL = %d\n",*caclsize))
|
|
}
|
|
|
|
|
|
// handle mode_exclusive a-henryw
|
|
if (_EditMode == MODE_MODIFY_EXCLUSIVE)
|
|
{
|
|
if (poldacl == NULL)
|
|
{
|
|
return ERROR_NO_MORE_ITEMS;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
|
|
SID *psid = NULL;
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
{
|
|
BOOL ffound = FALSE;
|
|
bDirEntryFound = FALSE;
|
|
for (ULONG cace = 0; cace < poldacl->AceCount;
|
|
cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
|
|
{
|
|
if ( (_aaa[j].option & OPTION_DENY ) ||
|
|
(_aaa[j].option & OPTION_REPLACE ) ||
|
|
(_aaa[j].option & OPTION_REVOKE ) ||
|
|
(_aaa[j].option & OPTION_GRANT))
|
|
{
|
|
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (EqualSid(psid,
|
|
(SID *)&((ACCESS_ALLOWED_ACE *)
|
|
pah)->SidStart) )
|
|
{
|
|
ffound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!ffound && psid)
|
|
{
|
|
*caclsize -= sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid);
|
|
_aaa[j].pcaa->ClearAccessMask();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:_AllocateNewAcl, private
|
|
//
|
|
// Synopsis: allocates and initializes the new ACL
|
|
//
|
|
// Arguments: OUT [pnewdacl] - address of new ACL to allocate
|
|
// IN [caclsize] - size to allocate for the new ACL
|
|
// IN [revision] - revision of the new ACL
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::_AllocateNewAcl(ACL **pnewdacl, ULONG caclsize, ULONG revision)
|
|
{
|
|
if (NULL == (*pnewdacl = (ACL *) LocalAlloc(LMEM_FIXED, caclsize)))
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
if (!InitializeAcl(*pnewdacl,caclsize, revision))
|
|
{
|
|
ULONG ret = GetLastError();
|
|
LocalFree(*pnewdacl);
|
|
return(ret);
|
|
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:_SetAllowedAce, private
|
|
//
|
|
// Synopsis: appends an allowed ACE to the input ACL
|
|
//
|
|
// Arguments: IN [dacl] - ACL to add the ACE to
|
|
// IN [mask] - access mask to add
|
|
// IN [psid] - SID to add
|
|
// IN [fdir] - if a Dir add inherit ACE as well
|
|
// IN [filespec] - if TRUE, no ACE for file will be written
|
|
// (directories only)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::_SetAllowedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir, ACCESS_MASK dirmask, BOOL filespec)
|
|
{
|
|
ULONG ret = ERROR_SUCCESS;
|
|
|
|
// compute the size of the ACE we are making
|
|
|
|
USHORT acesize = (USHORT)(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(psid));
|
|
|
|
SIZE((stderr, L"adding allowed ace, size = %d\n",fdir ? acesize*2 : acesize))
|
|
|
|
// static buffer in the hopes we won't have to allocate memory
|
|
|
|
BYTE buf[1024];
|
|
|
|
// allocator either uses buf or allocates a new buffer if size is not enough
|
|
|
|
FastAllocator fa(buf, 1024);
|
|
|
|
// get the buffer for the ACE
|
|
|
|
ACCESS_ALLOWED_ACE *paaa = (ACCESS_ALLOWED_ACE *)fa.GetBuf(acesize);
|
|
|
|
// fill in the ACE
|
|
|
|
memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
|
|
paaa->Mask = mask;
|
|
|
|
paaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
paaa->Header.AceSize = acesize;
|
|
|
|
// put the ACE into the ACL
|
|
|
|
if (!fdir)
|
|
{ paaa->Header.AceFlags = 0;
|
|
if (!AddAce(dacl,
|
|
dacl->AclRevision,
|
|
0xffffffff,
|
|
paaa,
|
|
paaa->Header.AceSize))
|
|
{ ret = GetLastError();
|
|
return (ret);
|
|
}
|
|
}
|
|
else
|
|
{ if (!filespec)
|
|
{ // if filespec is TRUE, the file inheritence is not specified
|
|
paaa->Header.AceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
|
|
if (!AddAce(dacl,
|
|
dacl->AclRevision,
|
|
0xffffffff,
|
|
paaa,
|
|
paaa->Header.AceSize))
|
|
{ ret = GetLastError();
|
|
return (ret);
|
|
}
|
|
}
|
|
|
|
paaa->Mask = dirmask;
|
|
paaa->Header.AceFlags = CONTAINER_INHERIT_ACE;
|
|
if (!AddAce(dacl,
|
|
dacl->AclRevision,
|
|
0xffffffff,
|
|
paaa,
|
|
paaa->Header.AceSize))
|
|
ret = GetLastError();
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:_SetDeniedAce, private
|
|
//
|
|
// Synopsis: appends a denied ACE to the input ACL
|
|
//
|
|
// Arguments: IN [dacl] - ACL to add the ACE to
|
|
// IN [mask] - access mask to add
|
|
// IN [psid] - SID to add
|
|
// IN [fdir] - if a Dir add inherit ACE as well
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::_SetDeniedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir)
|
|
{
|
|
ULONG ret = ERROR_SUCCESS;
|
|
|
|
// compute the size of the ACE we are making
|
|
|
|
USHORT acesize = (USHORT)( sizeof(ACCESS_DENIED_ACE) -
|
|
sizeof(DWORD) +
|
|
GetLengthSid(psid));
|
|
|
|
SIZE((stderr, L"adding denied ace, size = %d\n",acesize))
|
|
|
|
// static buffer in the hopes we won't have to allocate memory
|
|
|
|
BYTE buf[1024];
|
|
|
|
// allocator either uses buf or allocates a new buffer if size is not enough
|
|
|
|
FastAllocator fa(buf, 1024);
|
|
|
|
// get the buffer for the ACE
|
|
|
|
ACCESS_DENIED_ACE *paaa = (ACCESS_DENIED_ACE *)fa.GetBuf(acesize);
|
|
|
|
// fill in the ACE
|
|
|
|
memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
|
|
paaa->Mask = mask;
|
|
|
|
paaa->Header.AceType = ACCESS_DENIED_ACE_TYPE;
|
|
paaa->Header.AceFlags = fdir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE : 0;
|
|
paaa->Header.AceSize = acesize;
|
|
|
|
// put the ACE into the ACL
|
|
|
|
if (!AddAce(dacl,
|
|
dacl->AclRevision,
|
|
0xffffffff,
|
|
paaa,
|
|
paaa->Header.AceSize))
|
|
ret = GetLastError();
|
|
return(ret);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDaclWrap:_FillNewAcl, private
|
|
//
|
|
// Synopsis: The worker routine that actually fills the ACL, it adds the
|
|
// new denied ACEs, then if the new ACEs are being merged with
|
|
// an existing ACL, the existing ACL's ACE's (that don't
|
|
// conflict) are added, finally the new allowed ACEs are added.
|
|
// another ugly algorithm:
|
|
//
|
|
//for (new aces)
|
|
// if (new ace option == DENY)
|
|
// add new ace
|
|
//
|
|
//if (old aces)
|
|
// for (old aces)
|
|
// if (old ace mask != 0)
|
|
// add old ace
|
|
//
|
|
// for (new aces)
|
|
// if (new ace option != DENY)
|
|
// if ( new ace option != REVOKE)
|
|
// if (new ace mask != 0
|
|
// add new ace
|
|
//
|
|
//else
|
|
// for (new aces)
|
|
// if (new ace option != DENY)
|
|
// add new ace
|
|
//
|
|
// Arguments: IN [pnewdacl] - the new ACL to be filled
|
|
// IN [poldacl] - (OPTIONAL) old ACL that is to be merged
|
|
// IN [fdir] - TRUE = directory
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG CDaclWrap::_FillNewAcl(ACL *pnewdacl, ACL *poldacl, BOOL fdir)
|
|
{
|
|
SID *psid;
|
|
ULONG ret;
|
|
|
|
// set new denied aces
|
|
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
{
|
|
if (_aaa[j].option & OPTION_DENY)
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (ERROR_SUCCESS != (ret = _SetDeniedAce(pnewdacl,
|
|
_aaa[j].pcaa->AccessMask(),
|
|
psid,
|
|
fdir )))
|
|
return(ret);
|
|
} else
|
|
return(ret);
|
|
}
|
|
|
|
// should it be the new owner ?
|
|
if (_aaa[j].option & OPTION_SET_OWNER)
|
|
{ // remember the SID. If it's not empty, more than one has been specified to be the owner!
|
|
if (_powner)
|
|
{ // error, there can just be one...
|
|
printmessage( stdout, MSG_TWO_OWNER, 0 );
|
|
exit( -1 );
|
|
}
|
|
else
|
|
{ // get the descriptor and allocate the SID
|
|
SID_IDENTIFIER_AUTHORITY *pSIDAuth;
|
|
|
|
pSIDAuth = GetSidIdentifierAuthority( psid );
|
|
if (!AllocateAndInitializeSid( pSIDAuth, 0, 0, 0, 0, 0, 0, 0, 0, 0, &_powner ))
|
|
{ ret = GetLastError();
|
|
printmessage( stdout, ret, 0 );
|
|
exit( -1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check and see if the ACL from from the file is in correct format
|
|
|
|
if (poldacl)
|
|
{
|
|
SIZE((stderr, L"old ACL size = %d, acecount = %d\n",poldacl->AclSize,
|
|
poldacl->AceCount))
|
|
|
|
ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
|
|
|
|
// loop thru the old ACL, looking for matches with the new ACEs
|
|
|
|
BOOL fallowedacefound = FALSE;
|
|
for (ULONG cace = 0; cace < poldacl->AceCount;
|
|
cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
|
|
{
|
|
// error exit if the old ACL is incorrectly formated
|
|
|
|
if (pah->AceType == ACCESS_DENIED_ACE_TYPE && fallowedacefound)
|
|
{
|
|
VERBOSE((stderr, L"_FillNewAcl found an denied ACE after an allowed ACE\n"))
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
else if (pah->AceType == ACCESS_ALLOWED_ACE_TYPE)
|
|
fallowedacefound = TRUE;
|
|
|
|
// add the old ace to the new ACL if the old ace's mask is not zero
|
|
|
|
if ( 0 != (ACCESS_MASK)((ACCESS_ALLOWED_ACE *)pah)->Mask)
|
|
{
|
|
// add the old ace
|
|
if (!AddAce(pnewdacl,
|
|
pnewdacl->AclRevision,
|
|
0xffffffff,
|
|
pah,
|
|
pah->AceSize))
|
|
return(GetLastError());
|
|
}
|
|
}
|
|
// now for the new aces
|
|
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
{
|
|
if ( (_aaa[j].option != OPTION_DENY) &&
|
|
(_aaa[j].option != OPTION_REVOKE) &&
|
|
(_aaa[j].pcaa->AccessMask() != 0) )
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
|
|
_aaa[j].pcaa->AccessMask(),
|
|
psid,
|
|
fdir,
|
|
_aaa[j].pcaa->DirAccessMask(),
|
|
_aaa[j].pcaa->FileSpecified())))
|
|
return(ret);
|
|
} else
|
|
return(ret);
|
|
}
|
|
|
|
}
|
|
} else
|
|
{
|
|
// no old acl, just add the (rest) of the new aces
|
|
for (ULONG j = 0; j < _ccaa; j++)
|
|
{
|
|
if (_aaa[j].option != OPTION_DENY)
|
|
{
|
|
if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
|
|
{
|
|
if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
|
|
_aaa[j].pcaa->AccessMask(),
|
|
psid,
|
|
fdir,
|
|
_aaa[j].pcaa->DirAccessMask(),
|
|
_aaa[j].pcaa->FileSpecified())))
|
|
return(ret);
|
|
} else
|
|
return(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: printmessage
|
|
//
|
|
// Synopsis: prints a message, either from the local message file, or from the system
|
|
//
|
|
// Arguments: IN [fp] - stderr, stdio, etc.
|
|
// IN [messageID] - variable argument list
|
|
//
|
|
// Returns: length of the output buffer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
ULONG printmessage (FILE* fp, DWORD messageID, ...)
|
|
{
|
|
WCHAR messagebuffer[4096] = L"";
|
|
va_list ap;
|
|
|
|
va_start(ap, messageID);
|
|
|
|
if (!FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE,
|
|
NULL,
|
|
messageID,
|
|
0,
|
|
messagebuffer,
|
|
sizeof(messagebuffer)/sizeof(messagebuffer[0]),
|
|
&ap))
|
|
{
|
|
if(!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
messageID,
|
|
0,
|
|
messagebuffer,
|
|
sizeof(messagebuffer)/sizeof(messagebuffer[0]),
|
|
&ap))
|
|
{
|
|
va_end(ap);
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
fputws(messagebuffer,fp);
|
|
|
|
|
|
va_end(ap);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|