1052 lines
35 KiB
C++
1052 lines
35 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1995.
|
|
//
|
|
// File: accstg.cxx
|
|
//
|
|
// Contents: IAccessControl for files implementation
|
|
//
|
|
// History: 00-Mar-95 DaveMont Created
|
|
// 25-May-95 HenryLee Modified
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "headers.cxx"
|
|
#pragma hdrstop
|
|
|
|
#include <aclapi.h>
|
|
#include <accstg.hxx>
|
|
#include <ctype.h>
|
|
|
|
#define AccAlloc(x) LocalAlloc(LMEM_FIXED, x)
|
|
#ifndef AccFree
|
|
#define AccFree(x) LocalFree(x)
|
|
#endif
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::~CAccessControl
|
|
//
|
|
// Synopsis: Delete the object and set the deletion signature.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
CAccessControl::~CAccessControl()
|
|
{
|
|
if (m_grfMode & STGM_EDIT_ACCESS_RIGHTS)
|
|
{
|
|
if ((m_grfMode & STGM_TRANSACTED) == 0) // directmode only
|
|
CommitAccessRights(0);
|
|
if (m_pdacl)
|
|
AccFree(m_pdacl);
|
|
if (m_pdaclCommitted)
|
|
AccFree(m_pdaclCommitted);
|
|
|
|
CAccessControl *pAC = m_pACChild;
|
|
while (pAC != NULL)
|
|
{
|
|
CAccessControl *pACNext = pAC->m_pACNext;
|
|
pAC->m_pACParent = NULL; // mark parent as dead
|
|
pAC->Release(); // release the child
|
|
pAC = pACNext; // next child
|
|
|
|
}
|
|
if (m_pACParent != NULL) // if parent is still alive
|
|
m_pACParent->RemoveChild (this); // remove from parent's list
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::InitAccessControl
|
|
//
|
|
// Synopsis: Initialize the generic access control object.
|
|
//
|
|
// Arguments: [handle] File system handle
|
|
// [grfMode] Specifies transacted or direct mode
|
|
// [fGetDacl] Reads the DACL into memory
|
|
// [pACParent] parent for nested transactions
|
|
//
|
|
// Notes: The passed handle is saved to manipulate security
|
|
// descriptors.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
HRESULT CAccessControl::InitAccessControl (HANDLE handle,
|
|
DWORD grfMode,
|
|
BOOL fGetDacl,
|
|
CAccessControl *pACParent)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
m_handle = handle;
|
|
m_pdacl = NULL;
|
|
m_grfMode = grfMode & (~DF_REVERTED); // clear reverted bit
|
|
|
|
if (m_grfMode & STGM_EDIT_ACCESS_RIGHTS)
|
|
{
|
|
if ((pACParent != NULL) && (m_grfMode & STGM_TRANSACTED))
|
|
{
|
|
pACParent->InsertChild(this);
|
|
AddRef(); // hold on to child for nested commits
|
|
// released in parent's destructor
|
|
}
|
|
sc = InitializeCAcl (fGetDacl);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::GrantAccessRights, public
|
|
//
|
|
// Synopsis: grants the access requests to the current state of
|
|
// access control for the object. The access control
|
|
// will only be saved on the object if it is committed.
|
|
//
|
|
// Arguments: [cCount] - number of access requests in list
|
|
// [pAccessRequestList] - list of access requests
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::GrantAccessRights(ULONG cCount,
|
|
ACCESS_REQUEST pAccessRequestList[])
|
|
{
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::GrantAccessRights(%d, %x)\n",
|
|
cCount, pAccessRequestList));
|
|
|
|
SCODE sc = ApplyAccessRights(GRANT_ACCESS,
|
|
cCount,
|
|
pAccessRequestList,
|
|
&m_pdacl,
|
|
FALSE);
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CAccessControl::GrantAccessRights => (%d)\n",
|
|
sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::SetAccessRights, public
|
|
//
|
|
// Synopsis: sets the access requests to the current state of
|
|
// access control for the object. The access control
|
|
// will only be saved on the object if it is committed.
|
|
//
|
|
// Arguments: [cCount] - number of access requests in list
|
|
// [pAccessRequestList] - list of access requests
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::SetAccessRights(ULONG cCount,
|
|
ACCESS_REQUEST pAccessRequestList[])
|
|
{
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::SetAccessRights(%d, %x)\n",
|
|
cCount, pAccessRequestList));
|
|
|
|
SCODE sc = ApplyAccessRights(SET_ACCESS,
|
|
cCount,
|
|
pAccessRequestList,
|
|
&m_pdacl,
|
|
FALSE);
|
|
|
|
ssDebugOut((DEB_TRACE, "Out CAccessControl::SetAccessRights => (%d)\n",
|
|
sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::ReplaceAllAccessRights, public
|
|
//
|
|
// Synopsis: replaces all the access requests on the current state of
|
|
// access control for the object. The access control
|
|
// will only be saved on the object if it is committed.
|
|
//
|
|
// Arguments: [cCount] - number of access requests in list
|
|
// [pAccessRequestList] - list of access requests
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::ReplaceAllAccessRights(ULONG cCount,
|
|
ACCESS_REQUEST pAccessRequestList[])
|
|
{
|
|
ssDebugOut((DEB_TRACE,"In CAccessControl::ReplaceAllAccessRights(%d, %x)\n",
|
|
cCount, pAccessRequestList));
|
|
|
|
SCODE sc = ApplyAccessRights(SET_ACCESS,
|
|
cCount,
|
|
pAccessRequestList,
|
|
&m_pdacl,
|
|
TRUE);
|
|
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::ReplaceAllAccessRights =>(%d)\n",
|
|
sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::DenyAccessRights, public
|
|
//
|
|
// Synopsis: denies the access requests on the current state of
|
|
// access control for the object. The access control
|
|
// will only be saved on the object if it is committed.
|
|
//
|
|
// Arguments: [cCount] - number of access requests in list
|
|
// [pAccessRequestList] - list of access requests
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::DenyAccessRights(ULONG cCount,
|
|
ACCESS_REQUEST pAccessRequestList[])
|
|
{
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::DenyAccessRights(%d, %x)\n",
|
|
cCount, pAccessRequestList));
|
|
|
|
SCODE sc = ApplyAccessRights(DENY_ACCESS,
|
|
cCount,
|
|
pAccessRequestList,
|
|
&m_pdacl,
|
|
FALSE);
|
|
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::DenyAccessRights => (%d)\n",
|
|
sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::RevokeExplicitAccessRights, public
|
|
//
|
|
// Synopsis: revokes access control for the trustees from the current
|
|
// state of access control for the object. The access control
|
|
// will only be saved on the object if it is committed.
|
|
//
|
|
// Arguments: [cCount] - number of trustees in list
|
|
// [Trustee] - list of trustees
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::RevokeExplicitAccessRights(ULONG cCount,
|
|
TRUSTEE Trustee[])
|
|
{
|
|
ACCESS_REQUEST *par;
|
|
SCODE sc;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::RevokeExplicitAccessRights"
|
|
"(%d, %x)\n", cCount, Trustee));
|
|
|
|
if ((par = (ACCESS_REQUEST *)AccAlloc(cCount * sizeof(ACCESS_REQUEST))))
|
|
{
|
|
for (ULONG idx = 0; idx < cCount; idx++)
|
|
{
|
|
par[idx].grfAccessPermissions = 0;
|
|
par[idx].Trustee = Trustee[idx];
|
|
// Trustee name pointer is copied here
|
|
}
|
|
sc = ApplyAccessRights(REVOKE_ACCESS,
|
|
cCount,
|
|
par,
|
|
&m_pdacl,
|
|
FALSE);
|
|
|
|
AccFree(par);
|
|
}
|
|
else
|
|
sc = STG_E_INSUFFICIENTMEMORY;
|
|
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::RevokeExplicitAccessRights => "
|
|
"(%d)\n", sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::IsAccessPermitted, public
|
|
//
|
|
// Synopsis: determines if the trustee has the requested access permissions
|
|
// on the object
|
|
//
|
|
// Arguments: [Trustee] - Trustee name
|
|
// [grfAccessPermissions] - the requested permissions
|
|
//
|
|
// Returns: Appropriate status code
|
|
// S_OK == Access permitted, S_FALSE == Access denied
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Notes: does not check access given by privileges
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::IsAccessPermitted(TRUSTEE *pTrustee,
|
|
DWORD grfAccessPermissions)
|
|
|
|
{
|
|
SCODE sc = S_OK;
|
|
DWORD dwPermitted;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::IsAccessPermitted"
|
|
"(%d, %x)\n", grfAccessPermissions, pTrustee));
|
|
|
|
if (m_grfMode & DF_REVERTED)
|
|
sc = STG_E_REVERTED;
|
|
|
|
if (pTrustee == NULL || pTrustee->ptstrName == NULL)
|
|
{
|
|
sc = STG_E_INVALIDPARAMETER;
|
|
}
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
if (S_OK == (sc = GetEffectiveAccessRights(pTrustee,&dwPermitted)))
|
|
{
|
|
if (grfAccessPermissions == (grfAccessPermissions & dwPermitted))
|
|
sc = S_OK;
|
|
else
|
|
sc = S_FALSE;
|
|
}
|
|
}
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::IsAccessPermitted => "
|
|
"(%d)\n", sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::GetEffectiveAccessRights, public
|
|
//
|
|
// Synopsis: returns the effective access rights for the specified trustee
|
|
// on the object
|
|
//
|
|
// Arguments: [Trustee] - Trustee name
|
|
// [pgrfAccessPermissions] - effective access rights returned
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pgrfAccessPermissions]
|
|
//
|
|
// Notes: does not check access given by privileges
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::GetEffectiveAccessRights(TRUSTEE *pTrustee,
|
|
DWORD *pgrfAccessPermissions)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::GetEffectiveAccessRights"
|
|
"(%x, %x)\n", pgrfAccessPermissions, pTrustee));
|
|
|
|
if (m_grfMode & DF_REVERTED)
|
|
sc = STG_E_REVERTED;
|
|
|
|
if (pTrustee == NULL || pTrustee->ptstrName == NULL)
|
|
{
|
|
sc = STG_E_INVALIDPARAMETER;
|
|
}
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
if (S_OK == (sc = InitializeCAcl(TRUE)))
|
|
{
|
|
//
|
|
// lookup group ownerships
|
|
//
|
|
DWORD accessmask;
|
|
DWORD winerror;
|
|
|
|
if (NO_ERROR == (winerror = GetEffectiveRightsFromAcl(m_pdacl,
|
|
pTrustee,
|
|
&accessmask)))
|
|
{
|
|
*pgrfAccessPermissions = NTAccessMaskToProvAccessRights(
|
|
SE_FILE_OBJECT,
|
|
FALSE, //bugbug, iscontainer
|
|
accessmask);
|
|
} else
|
|
{
|
|
sc = WIN32_SCODE(winerror);
|
|
}
|
|
}
|
|
}
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::GetEffectiveAccessRights => "
|
|
"(%d)\n", sc));
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::GetExplicitAccessRights, public
|
|
//
|
|
// Synopsis: retrieves the DACL information
|
|
//
|
|
// Arguments: [pcCount] - number of ExplicitAccess entries
|
|
// [pExplicitAccessList] - list of Trustees and their perms
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: [pcCount, pExplicitAccessList]
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::GetExplicitAccessRights(ULONG *pcCount,
|
|
PEXPLICIT_ACCESS *pExplicitAccessList)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
ssDebugOut((DEB_TRACE, "In CAccessControl::GetExplicitAccessRights"
|
|
"(%x, %x)\n", pcCount, pExplicitAccessList));
|
|
|
|
if (m_grfMode & DF_REVERTED)
|
|
sc = STG_E_REVERTED;
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
if (S_OK == (sc = InitializeCAcl(TRUE)))
|
|
{
|
|
EXPLICIT_ACCESS *pExplicitAccess;
|
|
DWORD winerror;
|
|
|
|
if (NO_ERROR == (winerror = GetExplicitEntriesFromAcl(m_pdacl,
|
|
pcCount,
|
|
&pExplicitAccess)))
|
|
{
|
|
sc = Win32ExplicitAccessToExplicitAccess(*pcCount,
|
|
pExplicitAccess,
|
|
pExplicitAccessList);
|
|
AccFree(pExplicitAccess);
|
|
} else
|
|
{
|
|
sc = WIN32_SCODE(winerror);
|
|
}
|
|
}
|
|
|
|
}
|
|
ssDebugOut((DEB_TRACE,"Out CAccessControl::GetExplicitAccessRights => "
|
|
"(%d)\n", sc));
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::Commit, public
|
|
//
|
|
// Synopsis: Writes access control changes to disk
|
|
//
|
|
// Arguments: [grfCommitFlags] - future commit flags
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
// Notes: In transacted mode, save the committed state for nested transactions
|
|
// In direct mode, save to disk by calling CommitFromAbove
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::CommitAccessRights(DWORD grfCommitFlags)
|
|
{
|
|
SCODE sc = S_OK;
|
|
if (grfCommitFlags != 0)
|
|
ssErr (EH_Err, STG_E_INVALIDPARAMETER);
|
|
if (m_grfMode & DF_REVERTED)
|
|
ssErr (EH_Err, STG_E_REVERTED);
|
|
|
|
if ((m_grfMode & STGM_TRANSACTED) && m_pdacl != NULL)
|
|
{
|
|
// save the last commited state
|
|
if (m_pdaclCommitted != NULL)
|
|
AccFree (m_pdaclCommitted);
|
|
if ((m_pdaclCommitted = (ACL *) AccAlloc (m_pdacl->AclSize)) == 0)
|
|
ssErr (EH_Err, E_OUTOFMEMORY);
|
|
memcpy (m_pdaclCommitted, m_pdacl, m_pdacl->AclSize);
|
|
}
|
|
|
|
if (m_pACParent != NULL) // save only if at root level
|
|
ssErr (EH_Err, S_OK); // for non-root, get out
|
|
|
|
ssChk(CommitFromAbove()); // root level commit, walk the tree
|
|
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::RevertAccessRights, public
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
// Notes: Files only support the contents stream
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CAccessControl::RevertAccessRights()
|
|
{
|
|
SCODE sc = S_OK;
|
|
if ((m_grfMode & STGM_TRANSACTED))
|
|
{
|
|
if (m_pdacl)
|
|
{
|
|
AccFree(m_pdacl);
|
|
m_pdacl = NULL;
|
|
m_isdirty = FALSE;
|
|
}
|
|
if (m_pdaclCommitted)
|
|
{
|
|
m_pdacl = m_pdaclCommitted; // transfer the last committed state
|
|
m_pdaclCommitted = NULL; // to the current state
|
|
}
|
|
}
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccessRequestToExplicitAccess, private
|
|
//
|
|
// Synopsis: converts a list of access requests into access entries
|
|
//
|
|
// Arguments: IN [ObjectType] - the type of the object (eg.file,printer,etc.)
|
|
// IN [AccessMode] - the mode to apply access rights
|
|
// IN [cCountOfAccessRequests] - count of the access requests
|
|
// IN [pListOfAccessRequests] - the list of acccess requests
|
|
// OUT [pListOfExplicitAccess] - the list of acccess entries
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
// Notes: Files only support the contents stream
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CAccessControl::AccessRequestToExplicitAccess(
|
|
IN ACCESS_MODE AccessMode,
|
|
IN FILEDIR fd,
|
|
IN ACCESS_REQUEST *pListOfAccessRequests,
|
|
IN ULONG cCountOfAccessRequests,
|
|
OUT PEXPLICIT_ACCESS *pListOfExplicitAccess)
|
|
{
|
|
SCODE status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// if no requests, no entries
|
|
//
|
|
if (cCountOfAccessRequests > 0)
|
|
{
|
|
//
|
|
// allocate space for the access entries (passed to SetEntriesInAcl)
|
|
// note that we could just modify the mask in each entry, but then we
|
|
// would be modifying one of the callers in parameters.
|
|
//
|
|
if (NULL != (*pListOfExplicitAccess = (PEXPLICIT_ACCESS)
|
|
AccAlloc(cCountOfAccessRequests * sizeof(EXPLICIT_ACCESS))))
|
|
{
|
|
for (ULONG idx = 0; idx < cCountOfAccessRequests; idx++)
|
|
{
|
|
//
|
|
// set the access mode (same for all entries in this case
|
|
// set the inheritance
|
|
//
|
|
(*pListOfExplicitAccess)[idx].grfAccessMode = AccessMode;
|
|
if (fd == FD_DIR)
|
|
{
|
|
//
|
|
// bugbug, perhaps it might be better to make two aces
|
|
// (as the security editor does, since files and directories
|
|
// use different access masks)
|
|
//
|
|
(*pListOfExplicitAccess)[idx].grfInheritance =
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
|
} else
|
|
{
|
|
//
|
|
// no inheritance for files (and docfiles, etc.)
|
|
//
|
|
(*pListOfExplicitAccess)[idx].grfInheritance = NO_INHERITANCE;
|
|
}
|
|
//
|
|
// copy the trustee
|
|
//
|
|
(*pListOfExplicitAccess)[idx].Trustee =
|
|
pListOfAccessRequests[idx].Trustee;
|
|
//
|
|
// if impersonating, don't convert the mask as it may be
|
|
// object specific (in which case the object must make sure
|
|
// that the filesystem does not attempt to access check against
|
|
// it) To be specific, a server may want to define its own object
|
|
// specific permissions. In which case it puts an ACE at the front
|
|
// of the ACL that gives the server exclusive access to the file.
|
|
// The remaining ACEs are impersonate ACEs. When the server gets
|
|
// a client call on the object, the server opens the object. Then
|
|
// it impersonates and calls accesscheck on the object, using its
|
|
// own object specific permissions.
|
|
//
|
|
if (GetMultipleTrusteeOperation(&((*pListOfExplicitAccess)[idx].
|
|
Trustee)) == TRUSTEE_IS_IMPERSONATE)
|
|
{
|
|
//
|
|
// we don't copy the multiple trustee pointed to by the
|
|
// trustee
|
|
//
|
|
(*pListOfExplicitAccess)[idx].grfAccessPermissions =
|
|
pListOfAccessRequests[idx].grfAccessPermissions;
|
|
} else if (AccessMode != REVOKE_ACCESS)
|
|
{
|
|
//
|
|
// as long as not revoking access, make sure the input
|
|
// access mask is valid by checking the conversion
|
|
// to an NT mask for zero
|
|
//
|
|
if (0 == ((*pListOfExplicitAccess)[idx].grfAccessPermissions =
|
|
ProvAccessRightsToNTAccessMask(SE_FILE_OBJECT,
|
|
pListOfAccessRequests[idx].grfAccessPermissions)))
|
|
{
|
|
status = E_INVALIDARG;
|
|
AccFree(*pListOfExplicitAccess);
|
|
break;
|
|
}
|
|
//
|
|
// always add read_control and synchronize for allows since
|
|
// they overlap for all access requests.
|
|
//
|
|
if (AccessMode != DENY_ACCESS)
|
|
{
|
|
((*pListOfExplicitAccess)[idx].grfAccessPermissions) |=
|
|
(READ_CONTROL | SYNCHRONIZE);
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
status = STG_E_INSUFFICIENTMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STG_E_INVALIDPARAMETER;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: Win32ExplicitAccessToExplicitAccess, private
|
|
//
|
|
// Synopsis: converts a list of win32 explicit accesses into explicit accesses
|
|
//
|
|
// Arguments: IN [cCountOfExplicitAccess] - count of the access requests
|
|
// IN [pListOfExplicitAccess] - the list of access requests
|
|
// OUT [pListOfExplicitAccess] - the returned list of explicit access
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
// Notes: Files only support the contents stream
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CAccessControl::Win32ExplicitAccessToExplicitAccess(
|
|
IN ULONG cCountOfExplicitAccess,
|
|
IN PEXPLICIT_ACCESS pListOfWin32ExplicitAccess,
|
|
OUT PEXPLICIT_ACCESS *pListOfExplicitAccesses)
|
|
{
|
|
SCODE status = S_OK;
|
|
|
|
if (cCountOfExplicitAccess > 0)
|
|
{
|
|
//
|
|
// allocate space for the returned explicit accesses
|
|
//
|
|
if (NULL != (*pListOfExplicitAccesses = (EXPLICIT_ACCESS *)
|
|
CoTaskMemAlloc(cCountOfExplicitAccess * sizeof(EXPLICIT_ACCESS))))
|
|
{
|
|
for (ULONG idx = 0; idx < cCountOfExplicitAccess; idx++)
|
|
{
|
|
PEXPLICIT_ACCESS pea = &(*pListOfExplicitAccesses)[idx];
|
|
PEXPLICIT_ACCESS pWin32ea = &pListOfWin32ExplicitAccess[idx];
|
|
|
|
pea->grfAccessMode = pWin32ea->grfAccessMode;
|
|
pea->grfInheritance = pWin32ea->grfInheritance;
|
|
pea->Trustee = pWin32ea->Trustee;
|
|
//
|
|
// if it is an impersonate access request don't convert the mask
|
|
//
|
|
if (TRUSTEE_IS_IMPERSONATE == GetMultipleTrusteeOperation(&(pea->Trustee)))
|
|
{
|
|
pea->grfAccessPermissions = pWin32ea->grfAccessPermissions;
|
|
//
|
|
// allocate and fill the multiple trustee, fortunately this
|
|
// is only used for impersonate ACEs
|
|
//
|
|
if (NULL != (pea->Trustee.pMultipleTrustee = (PTRUSTEE)CoTaskMemAlloc(
|
|
sizeof(TRUSTEE))))
|
|
{
|
|
//
|
|
// copy the impersonate trustee
|
|
//
|
|
*(pea->Trustee.pMultipleTrustee) =
|
|
*(pWin32ea->Trustee.pMultipleTrustee);
|
|
//
|
|
// allocate space for the impersonate trustee name
|
|
//
|
|
if (pea->Trustee.pMultipleTrustee->ptstrName = (WCHAR *)
|
|
CoTaskMemAlloc((lstrlenW(pWin32ea->Trustee.pMultipleTrustee->ptstrName)+1)
|
|
*sizeof(WCHAR)))
|
|
{
|
|
//
|
|
// copy the name
|
|
//
|
|
lstrcpyW (pea->Trustee.pMultipleTrustee->ptstrName,
|
|
pWin32ea->Trustee.pMultipleTrustee->ptstrName);
|
|
} else
|
|
{
|
|
status = STG_E_INSUFFICIENTMEMORY;
|
|
//
|
|
// cleanup allocations
|
|
//
|
|
FreeStgExplicitAccessList(idx, *pListOfExplicitAccesses);
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
status = STG_E_INSUFFICIENTMEMORY;
|
|
//
|
|
// cleanup allocations
|
|
//
|
|
FreeStgExplicitAccessList(idx, *pListOfExplicitAccesses);
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
pea->grfAccessPermissions =
|
|
NTAccessMaskToProvAccessRights(SE_FILE_OBJECT,
|
|
FALSE, //bugbug iscontainer
|
|
pWin32ea->grfAccessPermissions);
|
|
}
|
|
if (pea->Trustee.ptstrName = (WCHAR *)
|
|
CoTaskMemAlloc((lstrlenW(pWin32ea->Trustee.ptstrName)+1)
|
|
*sizeof(WCHAR)))
|
|
{
|
|
lstrcpyW (pea->Trustee.ptstrName,
|
|
pWin32ea->Trustee.ptstrName);
|
|
} else
|
|
{
|
|
status = STG_E_INSUFFICIENTMEMORY;
|
|
//
|
|
// cleanup allocations
|
|
//
|
|
FreeStgExplicitAccessList(idx, *pListOfExplicitAccesses);
|
|
break;
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
status = STG_E_INSUFFICIENTMEMORY;
|
|
}
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: InitializeCAcl, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [fGetDacl] - controls whether DACL is read in
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
// Notes: DACL is read only when pdacl is NULL
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CAccessControl::InitializeCAcl(BOOL fGetDacl)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
|
|
PSECURITY_DESCRIPTOR psd;
|
|
PACL pdacl;
|
|
|
|
if (m_pdacl == NULL && fGetDacl)
|
|
{
|
|
DWORD dwStatus;
|
|
if (S_OK == (dwStatus = GetSecurityInfo(m_handle,
|
|
SE_FILE_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
&pdacl,
|
|
NULL,
|
|
&psd)))
|
|
{
|
|
if (NULL != (m_pdacl = (PACL) LocalAlloc(LMEM_FIXED, pdacl->AclSize)))
|
|
{
|
|
RtlCopyMemory(m_pdacl, pdacl, pdacl->AclSize);
|
|
} else
|
|
{
|
|
sc = E_OUTOFMEMORY;
|
|
}
|
|
AccFree(psd);
|
|
} else
|
|
{
|
|
sc = WIN32_SCODE(dwStatus);
|
|
}
|
|
}
|
|
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ApplyAccessRights, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [eAccessMode] - grant/deny/set/revoke/replaceall
|
|
// [cCount] - number of access requests
|
|
// [pAccessRequestList] - list of requests
|
|
// [pca] - the output CAcl class
|
|
// [pdacl] - the output ACL
|
|
// [fReplaceAll] - deletes old ACL before REPLACE_ALL_ACCESS
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Modifies: []
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CAccessControl::ApplyAccessRights(ACCESS_MODE eAccessMode,
|
|
ULONG cCount,
|
|
ACCESS_REQUEST *pAccessRequestList,
|
|
PACL *pdacl,
|
|
BOOL fReplaceAll)
|
|
|
|
{
|
|
SCODE status;
|
|
EXPLICIT_ACCESS *pea;
|
|
const BOOL bParanoid = FALSE;
|
|
//
|
|
// initialize the class and get the ACL if this is the first time
|
|
// When replacing all, there's no need to read the DACL
|
|
//
|
|
if (m_grfMode & DF_REVERTED)
|
|
return STG_E_REVERTED;
|
|
|
|
//
|
|
// if not replacing all, get the DACL
|
|
//
|
|
if (S_OK == (status = InitializeCAcl(!fReplaceAll)))
|
|
{
|
|
//
|
|
// convert the access request into something the
|
|
// acl management code understands
|
|
//
|
|
if (S_OK == (status = AccessRequestToExplicitAccess(eAccessMode,
|
|
FD_FILE,
|
|
pAccessRequestList,
|
|
cCount,
|
|
&pea)))
|
|
{
|
|
//
|
|
// if all the access entries are being replaced, delete
|
|
// the acl
|
|
//
|
|
if (fReplaceAll)
|
|
{
|
|
AccFree(*pdacl);
|
|
*pdacl = NULL;
|
|
}
|
|
ACL *pNewAcl;
|
|
DWORD winerror;
|
|
//
|
|
// set the access rights into the dacl
|
|
//
|
|
if (NO_ERROR == (winerror = SetEntriesInAcl(cCount, pea, *pdacl, &pNewAcl)))
|
|
{
|
|
//
|
|
// free the old dacl, make the new one the current one
|
|
//
|
|
if (*pdacl != NULL)
|
|
AccFree(*pdacl);
|
|
*pdacl = pNewAcl;
|
|
m_isdirty = TRUE;
|
|
if (bParanoid && // save every operation to disk
|
|
((m_grfMode & STGM_TRANSACTED) == 0)) // directmode
|
|
{
|
|
status = CommitAccessRights(0);
|
|
}
|
|
} else
|
|
{
|
|
status = WIN32_SCODE(winerror);
|
|
}
|
|
AccFree(pea);
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CommitFromAbove, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [none] -
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// Notes: In direct mode, commit the ACL to disk
|
|
// In transacted mode, commit the children and write the
|
|
// "last committed" version to disk.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CAccessControl::CommitFromAbove ()
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
// we have a nested transaction parent, commit the children
|
|
for (CAccessControl *pAC = m_pACChild; pAC; pAC = pAC->m_pACNext)
|
|
{
|
|
ssChk(pAC->CommitFromAbove());
|
|
}
|
|
|
|
if (m_grfMode & STGM_TRANSACTED) // save the last committed ACL
|
|
{
|
|
DWORD winerror;
|
|
|
|
if (NO_ERROR == (winerror = SetSecurityInfo(m_handle,
|
|
SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
|
|
NULL, NULL, m_pdaclCommitted, NULL)))
|
|
{
|
|
if (m_pdaclCommitted)
|
|
{
|
|
AccFree (m_pdaclCommitted);
|
|
m_pdaclCommitted = NULL;
|
|
}
|
|
} else
|
|
{
|
|
sc = WIN32_SCODE(winerror);
|
|
}
|
|
}
|
|
else // direct mode, save current state
|
|
{
|
|
if (m_isdirty)
|
|
{
|
|
DWORD winerror;
|
|
|
|
if (NO_ERROR == (winerror = SetSecurityInfo(m_handle,
|
|
SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
|
|
NULL, NULL, m_pdacl, NULL)))
|
|
{
|
|
//if (m_pdacl)
|
|
//{
|
|
// AccFree(m_pdacl);
|
|
// m_pdacl = NULL;
|
|
//}
|
|
m_isdirty = FALSE;
|
|
} else
|
|
{
|
|
sc = WIN32_SCODE(winerror);
|
|
}
|
|
}
|
|
|
|
}
|
|
EH_Err:
|
|
return ssResult(sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::InsertChild
|
|
//
|
|
// Synopsis: insert into child list for nested transactions
|
|
//
|
|
// Arguments: [pACChild] child object
|
|
//
|
|
// Notes: does not detect duplicates
|
|
//
|
|
//+-------------------------------------------------------------------
|
|
HRESULT CAccessControl::InsertChild (CAccessControl *pACChild)
|
|
{
|
|
ssAssert (pACChild != NULL);
|
|
// BUGBUG lock this
|
|
pACChild->m_pACNext = m_pACChild;
|
|
pACChild->m_pACParent = this;
|
|
m_pACChild = pACChild;
|
|
// BUGBUG unlock this
|
|
|
|
return ssResult(S_OK);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessControl::RemoveChild
|
|
//
|
|
// Synopsis: removes a child list from nested transactions
|
|
//
|
|
// Arguments: [pACChild] child object
|
|
//
|
|
// Notes: does not remove/detect duplicates
|
|
//
|
|
//+-------------------------------------------------------------------
|
|
HRESULT CAccessControl::RemoveChild (CAccessControl *pACChild)
|
|
{
|
|
SCODE sc = S_OK;
|
|
ssAssert (pACChild != NULL);
|
|
if (m_pACChild == pACChild) // remove from front of list
|
|
{
|
|
// BUGBUG lock this
|
|
m_pACChild = pACChild->m_pACNext;
|
|
pACChild->m_pACNext = NULL;
|
|
// BUGBUG unlock this
|
|
}
|
|
else
|
|
{
|
|
for (CAccessControl *pAC = m_pACChild; pAC; pAC = pAC->m_pACNext)
|
|
{
|
|
if (pAC->m_pACNext == pACChild)
|
|
{
|
|
// BUGBUG lock pAC
|
|
pAC->m_pACNext = pACChild->m_pACNext;
|
|
pACChild->m_pACNext = NULL;
|
|
// BUGBUG unlock pAC
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ssResult(S_OK);
|
|
}
|