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.
3420 lines
103 KiB
3420 lines
103 KiB
//******************************************************************************
|
|
//
|
|
// Microsoft Confidential. Copyright (c) Microsoft Corporation 1999. All rights reserved
|
|
//
|
|
// File: ChkAcc.cpp
|
|
//
|
|
// Description: RSOP Security functions
|
|
//
|
|
// History: 31-Jul-99 leonardm Created
|
|
//
|
|
//******************************************************************************
|
|
|
|
#include "uenv.h"
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <Windows.h>
|
|
#include <DsGetDC.h>
|
|
#include <authzi.h>
|
|
#include "ChkAcc.h"
|
|
#include "smartptr.h"
|
|
#include "RsopUtil.h"
|
|
#include "RsopDbg.h"
|
|
|
|
|
|
CDebug dbgAccessCheck( L"Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon",
|
|
L"ChkAccDebugLevel",
|
|
L"ChkAcc.log",
|
|
L"ChkAcc.bak",
|
|
TRUE );
|
|
|
|
#undef dbg
|
|
#define dbg dbgAccessCheck
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Class: CSid
|
|
//
|
|
// Description: Objects of this class encapsulate and simplify manipulation of
|
|
// SIDs for the purposes of access control checks.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
class CSid
|
|
{
|
|
private:
|
|
bool m_bState; // Flag to indicate whether the object is currently
|
|
// associated with a valid SID.
|
|
|
|
PSID m_pSid; // Pointer to the SID encapsulated by thi class.
|
|
|
|
CWString m_sUser; // User name
|
|
CWString m_sDomain; // Domain where the user account resides.
|
|
CWString m_sComputer; // Computer in the domain where the user account exists
|
|
|
|
CWString m_sSidString; // String representation of the encapsulated SID.
|
|
|
|
SID_NAME_USE m_eUse; // SID type.
|
|
|
|
public:
|
|
|
|
//
|
|
// Overloaded constructors
|
|
//
|
|
|
|
CSid() : m_bState(false), m_pSid(NULL), m_eUse(SidTypeUnknown){}
|
|
|
|
CSid(const PSID pSid, const WCHAR* szComputer = NULL ) :
|
|
m_bState(false),
|
|
m_pSid(NULL),
|
|
m_eUse(SidTypeUnknown)
|
|
{
|
|
Initialize(pSid, szComputer);
|
|
}
|
|
|
|
CSid(const WCHAR* szUser, const WCHAR* szComputer = NULL ) :
|
|
m_bState(false),
|
|
m_pSid(NULL),
|
|
m_eUse(SidTypeUnknown)
|
|
{
|
|
Initialize(szUser, szComputer);
|
|
}
|
|
|
|
CSid(const CSid& otherSid) :
|
|
m_bState(false),
|
|
m_pSid(NULL),
|
|
m_eUse(SidTypeUnknown)
|
|
{
|
|
Initialize(otherSid.User(), otherSid.Computer());
|
|
}
|
|
|
|
~CSid()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
|
|
//
|
|
// Attempts to initialize an object of this class by associating it with
|
|
// an existing user represented in the SID pointed to by pSid.
|
|
//
|
|
|
|
bool Initialize(PSID pSid, const WCHAR* szComputer = NULL);
|
|
|
|
|
|
//
|
|
// Attempts to initialize an object of this class by associating it with
|
|
// an existing user represented by szUser.
|
|
//
|
|
|
|
bool Initialize(const WCHAR* szUser, const WCHAR* szComputer = NULL);
|
|
|
|
|
|
//
|
|
// Indicates whether this object is currently associated with a valid user.
|
|
//
|
|
|
|
bool IsValid() const{ return m_bState; }
|
|
|
|
|
|
//
|
|
// Overload of assignment operator. Copies one CSid to another.
|
|
// After a this call two objects encapsulate the same SID.
|
|
// However, each owns its own memory. So the destructor of
|
|
// one object can be called without invalidating resources used by the other.
|
|
//
|
|
|
|
CSid& operator = (CSid otherSid);
|
|
|
|
|
|
//
|
|
// Overload of assignment operator. Initializes
|
|
// the current object with an existing SID.
|
|
//
|
|
|
|
CSid& operator = (PSID pSid);
|
|
|
|
|
|
//
|
|
// Returns a pointer to the SID encapsulated by this object.
|
|
//
|
|
|
|
PSID GetSidPtr() const{ return m_pSid; }
|
|
|
|
|
|
//
|
|
// Returns the name of the user associated with this object.
|
|
//
|
|
|
|
const WCHAR* User() const{ return m_sUser; }
|
|
|
|
|
|
//
|
|
// Returns the name of the computer used to Initialize this object with a user.
|
|
//
|
|
|
|
const WCHAR* Computer() const{ return m_sComputer; }
|
|
|
|
|
|
//
|
|
// Returns the name of the domain of which the user is a member.
|
|
//
|
|
|
|
const WCHAR* Domain() const{ return m_sDomain; }
|
|
|
|
|
|
//
|
|
// Returns a the SID associated with object in
|
|
// a string format suitable for display
|
|
//
|
|
|
|
const WCHAR* SidString() const{ return m_sSidString; }
|
|
|
|
|
|
//
|
|
// Returns the type as it was found in the SID associated
|
|
// with this object during processing of Initialize.
|
|
//
|
|
|
|
SID_NAME_USE SidType() const{ return m_eUse; }
|
|
|
|
|
|
//
|
|
// Breaks the association of this object with an exisitng SID. Releases
|
|
// memory allocate during Initialize and set the internal state to Invalid.
|
|
// This call is safe even if the object is not initialized.
|
|
//
|
|
|
|
void Reset();
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSid::Initialize
|
|
//
|
|
// Description: Attempts to initialize an object of this class by associating it with
|
|
// an existing user represented in the SID pointed to by pSid.
|
|
//
|
|
// Parameters: - pSid: Pointer to an exisitng SID. The memory pointed to
|
|
// by this parameter may be released after a call to
|
|
// this function since objects of this class allocate
|
|
// and release their own memory for the associated SID.
|
|
// - szComputer: Pointer to a string naming the computer where the
|
|
// lookup of the account is to take place. If NULL, the
|
|
// curent computer is used.
|
|
//
|
|
// Return: true on success. false otherwise.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
bool CSid::Initialize(const PSID pSid, const WCHAR* szComputer/* = NULL */)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CSid::Initialize - Entering...");
|
|
|
|
Reset();
|
|
|
|
if(!IsValidSid(pSid))
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - IsValidSid returned false!");
|
|
return m_bState;
|
|
}
|
|
|
|
m_pSid = new BYTE[GetLengthSid(pSid)];
|
|
|
|
if(!m_pSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - call to new failed!");
|
|
return m_bState;
|
|
}
|
|
|
|
BOOL bRes = CopySid(GetLengthSid(pSid), m_pSid, pSid);
|
|
if(!bRes)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - Call to CopySid returned FALSE!");
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
|
|
DWORD cbUser = 0;
|
|
DWORD cbDomain = 0;
|
|
|
|
LookupAccountSid(szComputer, m_pSid, NULL, &cbUser, NULL, &cbDomain, &m_eUse);
|
|
if(cbUser && cbDomain)
|
|
{
|
|
XPtrST<WCHAR>xpszUser = new WCHAR[cbUser];
|
|
|
|
if(!xpszUser)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - call to new failed!");
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
XPtrST<WCHAR>xpszDomain = new WCHAR[cbDomain];
|
|
|
|
if(!xpszDomain)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - call to new failed!");
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
bRes = LookupAccountSid(szComputer, m_pSid, xpszUser, &cbUser, xpszDomain, &cbDomain, &m_eUse);
|
|
|
|
if(!bRes)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - call to LookupAccountSid returned FALSE!");
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sUser = xpszUser;
|
|
if(!m_sUser.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sDomain = xpszDomain;
|
|
if(!m_sDomain.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
XPtrLF<WCHAR>szSidString = NULL;
|
|
bRes = ConvertSidToStringSid(m_pSid, &szSidString);
|
|
if(!bRes)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CSid::Initialize - call to ConvertSidToStringSid returned false!");
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sSidString = szSidString;
|
|
if(!m_sSidString.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_bState = true;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CSid::Initialize - Leaving successfully.");
|
|
return m_bState;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSid::Initialize
|
|
//
|
|
// Description: Attempts to initialize an object of this class by associating it with
|
|
// an existing user represented by szUser.
|
|
//
|
|
// Parameters: - szUser: Name of an existing user.
|
|
// - szComputer: Pointer to a string naming the computer where the
|
|
// lookup of the account is to take place. If NULL, the
|
|
// curent computer is used.
|
|
//
|
|
// Return: true on success. false otherwise.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
bool CSid::Initialize(const WCHAR* szUser, const WCHAR* szComputer/* = NULL */)
|
|
{
|
|
Reset();
|
|
|
|
if(!szUser)
|
|
{
|
|
return m_bState;
|
|
}
|
|
|
|
m_sUser = szUser;
|
|
if(!m_sUser.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sComputer = szComputer ? szComputer : L"";
|
|
if(!m_sComputer.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
DWORD cSid = 0;
|
|
|
|
DWORD cDomain = 0;
|
|
|
|
LookupAccountName(szComputer, szUser, NULL, &cSid, NULL, &cDomain, &m_eUse);
|
|
|
|
if(cSid && cDomain)
|
|
{
|
|
m_pSid = new BYTE[cSid];
|
|
if(!m_pSid)
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
XPtrST<WCHAR>xpszDomain = new WCHAR[cDomain];
|
|
|
|
if(!xpszDomain)
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
BOOL bRes = LookupAccountName(szComputer, szUser, m_pSid, &cSid, xpszDomain, &cDomain, &m_eUse);
|
|
|
|
if(!bRes)
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sDomain = xpszDomain;
|
|
if(!m_sDomain.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
XPtrLF<WCHAR>szSidString = NULL;
|
|
bRes = ConvertSidToStringSid(m_pSid, &szSidString);
|
|
if(!bRes)
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_sSidString = szSidString;
|
|
if(!m_sSidString.ValidString())
|
|
{
|
|
Reset();
|
|
return m_bState;
|
|
}
|
|
|
|
m_bState = true;
|
|
}
|
|
|
|
return m_bState;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: Reset
|
|
//
|
|
// Description: Breaks the association of this object with an exisitng SID. Releases
|
|
// memory allocate during Initialize and set the internal state to Invalid.
|
|
// This call is safe even if the object is not initialized.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void CSid::Reset()
|
|
{
|
|
delete[] (BYTE*)m_pSid;
|
|
|
|
m_pSid = NULL;
|
|
|
|
m_sUser = m_sDomain = m_sComputer = m_sSidString = L"";
|
|
|
|
m_eUse = SidTypeUnknown;
|
|
|
|
m_bState = false;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: operator =
|
|
//
|
|
// Description: Overload of assignment operator. Copies one CSid to another.
|
|
// After a this call two objects encapsulate the same SID.
|
|
// However, each owns its own memory. So the destructor of
|
|
// one object can be called without invalidating resources used by the other.
|
|
//
|
|
// Parameters: - otherSid: The CSid whose value is to be copied.
|
|
//
|
|
// Return: A reference to the object on which the call is invoked.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CSid& CSid::operator = (CSid otherSid)
|
|
{
|
|
if(this == &otherSid)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
Reset();
|
|
|
|
if(!IsValidSid(otherSid.GetSidPtr()))
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
Initialize(otherSid.User(), otherSid.Computer());
|
|
|
|
return *this;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: operator =
|
|
//
|
|
// Description: Overload of assignment operator. Initializes the current object with
|
|
// an existing SID.
|
|
//
|
|
// Parameters: - otherSid: The CSid whose value is to be copied.
|
|
//
|
|
// Return: A reference to the object on which the call is invoked.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CSid& CSid::operator = (PSID pSid)
|
|
{
|
|
Reset();
|
|
|
|
if(!IsValidSid(pSid))
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
Initialize(pSid);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Structure: CTLink
|
|
//
|
|
// Description:
|
|
//
|
|
// History: 8/02/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
template<typename T> struct CTLink
|
|
{
|
|
T* m_pData;
|
|
CTLink* m_pNext;
|
|
CTLink* m_pPrev;
|
|
CTLink(T* pData) : m_pData(pData), m_pNext(NULL), m_pPrev(NULL){}
|
|
~CTLink()
|
|
{
|
|
delete m_pData;
|
|
}
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Structure: CRsopToken
|
|
//
|
|
// Description: This reprents a pseudo-token containing an arbitrary
|
|
// combination of SIDs which
|
|
// can be used to check access to objects protected with security descriptors.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
struct CRsopToken
|
|
{
|
|
CTLink<CSid>* m_pSidsHead;
|
|
CTLink<CSid>* m_pSidsTail;
|
|
|
|
|
|
//
|
|
// Default constructor. Constructs an object with no sids. Access checks
|
|
// against an CRsopToken with no SIDs will always fail; even on objects
|
|
// with no DACL.
|
|
//
|
|
|
|
CRsopToken() : m_pSidsHead(NULL), m_pSidsTail(NULL) {}
|
|
|
|
|
|
//
|
|
// Destructor. Releases the memory pointed
|
|
// to by each of the elements of m_pSidsHead.
|
|
//
|
|
|
|
~CRsopToken();
|
|
|
|
|
|
//
|
|
// Adds a CSid to this object. The client of this class allocates the memory
|
|
// for the CSid and this class releases the memory in the destructor.
|
|
//
|
|
|
|
HRESULT AddSid(CSid* pSid);
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CRsopToken::~CRsopToken
|
|
//
|
|
// Description: Destructor. Releases the memory pointed to by each of the elements of
|
|
// m_pSidsHead.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: N/A
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CRsopToken::~CRsopToken()
|
|
{
|
|
CTLink<CSid>* pLinkIterator = m_pSidsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
CTLink<CSid>* pLinkToDelete = pLinkIterator;
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
delete pLinkToDelete;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CRsopToken::AddSid
|
|
//
|
|
// Description: Adds a CSid to this object. The client of this class allocates the
|
|
// memory for the CSid and this class releases the memory in the destructor.
|
|
//
|
|
// Parameters: - pSid: A pointer to a CSid. The memory pointed to by pSid will be released by
|
|
// in the destructor.
|
|
//
|
|
// Return: On success it returns S_OK.
|
|
// On failure it returns E_OUTOFMEMORY.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT CRsopToken::AddSid(CSid* pSid)
|
|
{
|
|
|
|
//
|
|
// first check if the Sid is already in there
|
|
//
|
|
for(CTLink<CSid>* pTraverseLink = m_pSidsHead; pTraverseLink; pTraverseLink = pTraverseLink->m_pNext)
|
|
{
|
|
//
|
|
// If one of the SIDs in the RsopToken matches
|
|
// this Sid, return
|
|
//
|
|
|
|
if (EqualSid(pSid->GetSidPtr(), pTraverseLink->m_pData->GetSidPtr()))
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate a new link using the pSid passed in.
|
|
//
|
|
|
|
CTLink<CSid>* pLink = new CTLink<CSid>(pSid);
|
|
if(!pLink)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!m_pSidsHead)
|
|
{
|
|
m_pSidsHead = pLink;
|
|
}
|
|
else
|
|
{
|
|
m_pSidsTail->m_pNext = pLink;
|
|
}
|
|
|
|
m_pSidsTail = pLink;
|
|
|
|
return S_OK;
|
|
}
|
|
//******************************************************************************
|
|
//
|
|
// Function: GetUserInfo
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/7/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT GetUserInfo(const CWString& sUser,
|
|
CWString& sUserName,
|
|
CWString& sUserDomain,
|
|
CWString& sUserDC)
|
|
{
|
|
if(!sUser.ValidString())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
NET_API_STATUS status;
|
|
|
|
XPtrST<WCHAR>xpUserName = NULL;
|
|
XPtrST<WCHAR>xpUserDomain = NULL;
|
|
|
|
size_t len = sUser.length();
|
|
|
|
WCHAR* backslashPos = wcschr(sUser, L'\\');
|
|
if(backslashPos)
|
|
{
|
|
size_t index = backslashPos - sUser;
|
|
xpUserDomain = new WCHAR[index + 1];
|
|
if(!xpUserDomain )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcsncpy(xpUserDomain, sUser, index);
|
|
xpUserDomain[index] = L'\0';
|
|
|
|
xpUserName = new WCHAR[len - index];
|
|
if(!xpUserName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcsncpy(xpUserName, backslashPos + 1, len - index - 1);
|
|
xpUserName[len - index - 1] = L'\0';
|
|
}
|
|
|
|
sUserName = xpUserName ? CWString(xpUserName) : sUser;
|
|
if(!sUserName.ValidString())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(xpUserDomain)
|
|
{
|
|
// Use supplied domain.
|
|
sUserDomain = xpUserDomain;
|
|
}
|
|
else
|
|
{
|
|
// Use current domain
|
|
WKSTA_INFO_100* pWkstaInfo = NULL;
|
|
status = NetWkstaGetInfo(NULL,100,(LPBYTE*)&pWkstaInfo);
|
|
if(status != NERR_Success)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
sUserDomain = pWkstaInfo->wki100_langroup;
|
|
NetApiBufferFree(pWkstaInfo);
|
|
}
|
|
|
|
if(!sUserDomain.ValidString())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
PDOMAIN_CONTROLLER_INFO pDCInfo = 0;
|
|
|
|
DWORD dwError = DsGetDcName(0,
|
|
sUserDomain,
|
|
0,
|
|
0,
|
|
0,
|
|
&pDCInfo );
|
|
if ( dwError != NO_ERROR )
|
|
{
|
|
return HRESULT_FROM_WIN32( dwError );
|
|
}
|
|
|
|
sUserDC = pDCInfo->DomainControllerName;
|
|
|
|
NetApiBufferFree(pDCInfo);
|
|
|
|
if ( !sUserDC.ValidString() )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: AddSpecialGroup
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/7/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT AddSpecialGroup(PRSOPTOKEN pRsopToken, PSID pSid)
|
|
{
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
|
|
XPtrST<CSid> xpCSid = new CSid(pSid);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!xpCSid->IsValid())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hr = pToken->AddSid(xpCSid);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: AddSpecialGroups
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/7/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT AddSpecialGroups(PRSOPTOKEN pRsopToken )
|
|
{
|
|
BOOL bRes;
|
|
PSID pSid;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Everyone
|
|
//
|
|
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority_World = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
bRes = AllocateAndInitializeSid(&IdentifierAuthority_World, 1,
|
|
SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pSid);
|
|
|
|
if(!bRes)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = AddSpecialGroup(pRsopToken, pSid);
|
|
|
|
FreeSid(pSid);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Authenticated users
|
|
//
|
|
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority_NT = SECURITY_NT_AUTHORITY;
|
|
|
|
bRes = AllocateAndInitializeSid(&IdentifierAuthority_NT, 1,
|
|
SECURITY_AUTHENTICATED_USER_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pSid);
|
|
|
|
if(!bRes)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = AddSpecialGroup(pRsopToken, pSid);
|
|
|
|
FreeSid(pSid);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: AddGlobalGroups
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/7/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT AddGlobalGroups(const CWString& sUserName,
|
|
const CWString& sUserDC,
|
|
PRSOPTOKEN pRsopToken)
|
|
{
|
|
if(!sUserName.ValidString())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
|
|
BYTE* pBuffer = NULL;
|
|
DWORD dwEntriesread;
|
|
DWORD dwTotalentries;
|
|
|
|
NET_API_STATUS result = NetUserGetGroups( sUserDC,
|
|
sUserName,
|
|
0,
|
|
&pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&dwEntriesread,
|
|
&dwTotalentries);
|
|
|
|
if(result != NERR_Success)
|
|
{
|
|
return HRESULT_FROM_WIN32(result);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
GROUP_USERS_INFO_0* pGui = (GROUP_USERS_INFO_0*)pBuffer;
|
|
|
|
XPtrST<CSid> xpCSid;
|
|
|
|
for(DWORD dwi = 0; dwi < dwEntriesread; dwi++)
|
|
{
|
|
xpCSid = new CSid((pGui[dwi]).grui0_name);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
if(!xpCSid->IsValid())
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
hr = pToken->AddSid(xpCSid);
|
|
if(FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
}
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: AddLocalGroups
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
//
|
|
//******************************************************************************
|
|
HRESULT AddLocalGroups(const CWString& sUserName,
|
|
const CWString& sUserDC,
|
|
PRSOPTOKEN pRsopToken)
|
|
{
|
|
if(!sUserName.ValidString())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
|
|
BYTE* pBuffer = NULL;
|
|
DWORD dwEntriesread;
|
|
DWORD dwTotalentries;
|
|
|
|
NET_API_STATUS result = NetUserGetLocalGroups(
|
|
sUserDC,
|
|
sUserName,
|
|
0,
|
|
LG_INCLUDE_INDIRECT,
|
|
&pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&dwEntriesread,
|
|
&dwTotalentries);
|
|
|
|
if(result != NERR_Success)
|
|
{
|
|
HRESULT_FROM_WIN32(result);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
LPLOCALGROUP_USERS_INFO_0 pLui = (LPLOCALGROUP_USERS_INFO_0)pBuffer;
|
|
|
|
XPtrST<CSid> xpCSid;
|
|
|
|
for(DWORD dwi = 0; dwi < dwEntriesread; dwi++)
|
|
{
|
|
xpCSid = new CSid((pLui[dwi]).lgrui0_name);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
if(!xpCSid->IsValid())
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
hr = pToken->AddSid(xpCSid);
|
|
if(FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
}
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: ExpandGroup
|
|
//
|
|
// Description: Expands a given group by expanding to include all the member subgroups etc..
|
|
//
|
|
// Parameters: - pRsopToken: Rsop token
|
|
// hAuthz: A pointer to the Authz resource manager
|
|
// (that we are using to expand the grps)
|
|
// pCSid: Sid of the group
|
|
//
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
//******************************************************************************
|
|
|
|
HRESULT ExpandGroup(CRsopToken *pRsopToken, AUTHZ_RESOURCE_MANAGER_HANDLE hAuthz,
|
|
CSid *pCSid )
|
|
{
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzContext=0;
|
|
LUID luid = {0};
|
|
HRESULT hrRet = S_OK;
|
|
DWORD dwSize=0;
|
|
XPtrLF<TOKEN_GROUPS> xGrps;
|
|
XPtrST<CSid> xpCSid;
|
|
|
|
|
|
if (!AuthziInitializeContextFromSid(0,
|
|
pCSid->GetSidPtr(),
|
|
hAuthz,
|
|
NULL,
|
|
luid, // we are not using it
|
|
NULL,
|
|
&hAuthzContext)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ExpandGroup - AuthziInitializeContextFromSid failed. Error - %d", GetLastError());
|
|
hrRet = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Now get the list of expanded sids
|
|
// find the size first
|
|
//
|
|
|
|
if (!AuthzGetInformationFromContext(hAuthzContext,
|
|
AuthzContextInfoGroupsSids,
|
|
NULL,
|
|
&dwSize,
|
|
0)) {
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ExpandGroup - AuthzGetInformationFromContext failed. Error - %d", GetLastError());
|
|
hrRet = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
xGrps = (PTOKEN_GROUPS)LocalAlloc(LPTR, dwSize);
|
|
|
|
if (!xGrps) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ExpandGroup - Couldn't allocate memory for the token grps. Error - %d", GetLastError());
|
|
hrRet = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
if (!AuthzGetInformationFromContext(hAuthzContext,
|
|
AuthzContextInfoGroupsSids,
|
|
dwSize,
|
|
&dwSize,
|
|
xGrps)) {
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - AuthzGetInformationFromContext(2) failed. Error - %d", GetLastError());
|
|
hrRet = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
for (DWORD i = 0; i < xGrps->GroupCount; i++) {
|
|
xpCSid = new CSid(xGrps->Groups[i].Sid, NULL);
|
|
|
|
if (!xpCSid) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - couldn't allocate memory(2). Error - %d", GetLastError());
|
|
hrRet = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
hrRet = pRsopToken->AddSid(xpCSid);
|
|
if(FAILED(hrRet)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - AddSid failed. Error - 0x%x", hrRet);
|
|
goto Exit;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
}
|
|
|
|
hrRet = S_OK;
|
|
|
|
Exit:
|
|
if (hAuthzContext)
|
|
AuthzFreeContext(hAuthzContext);
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: RsopCreateToken
|
|
//
|
|
// Description: Creates a pseudo-token using an exisitng user or machine account plus
|
|
// the accounts of which that user is currently a member of.
|
|
// The returned pseudo-token can be used subsequently in call
|
|
// to other RSOP security functions to check access to
|
|
// objects protected by security descriptors.
|
|
//
|
|
// Parameters: - szaccountName: Pointer to a user or machine account name.
|
|
// - psaUserSecurityGroups: Pointer ta SAFEARRAY of BSTRs representing
|
|
// security groups.
|
|
// If NULL, then all the current security groups for the
|
|
// szaccountName are added to the RsopToken.
|
|
// If not NULL but pointing to an empty array,
|
|
// only the szaccountName is added to the RsopToken.
|
|
// - ppRsopToken: Address of a PRSOPTOKEN that receives the newly
|
|
// created pseudo-token
|
|
//
|
|
//
|
|
// Return: S_OK if successful. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/7/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT RsopCreateToken(WCHAR* szAccountName,
|
|
SAFEARRAY* psaUserSecurityGroups,
|
|
PRSOPTOKEN* ppRsopToken )
|
|
{
|
|
|
|
|
|
dbg.Initialize( L"Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon",
|
|
L"ChkAccDebugLevel",
|
|
L"ChkAcc.log",
|
|
L"ChkAcc.bak");
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopCreateToken - Entering...");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
//
|
|
// Instantiate a new CRsopToken
|
|
//
|
|
|
|
*ppRsopToken = NULL;
|
|
|
|
XPtrST<CRsopToken>xpRsopToken = new CRsopToken();
|
|
|
|
if(!xpRsopToken)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - Operator new returned NULL. Creation of a CRsopToken failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Add to the new CRsopToken a CSid corresponding to the
|
|
// principal represented by parameter szAccountName. For
|
|
// dummy target the szAccountName will be null.
|
|
//
|
|
|
|
XPtrST<CSid>xpCSid;
|
|
|
|
if ( szAccountName )
|
|
{
|
|
xpCSid = new CSid(szAccountName);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - Operator new returned NULL. Creation of a CSid failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!xpCSid->IsValid())
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - Call to CSid::IsValid failed.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = xpRsopToken->AddSid(xpCSid);
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
}
|
|
|
|
//
|
|
// If the parameter is NULL, that means we are to add the security
|
|
// groups to which the user currently belongs.
|
|
//
|
|
|
|
if(!psaUserSecurityGroups)
|
|
{
|
|
if (szAccountName) {
|
|
CWString sUser = szAccountName;
|
|
CWString sUserName;
|
|
CWString sUserDomain;
|
|
CWString sUserDC;
|
|
|
|
hr = GetUserInfo(sUser, sUserName, sUserDomain, sUserDC);
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
/* for cross domain cases this fails
|
|
|
|
//
|
|
// Get Global group membership
|
|
//
|
|
hr = AddGlobalGroups(sUserName, sUserDC, xpRsopToken);
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
*/
|
|
|
|
hr = AddLocalGroups(sUserName, sUserDC, xpRsopToken);
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Universal groups across domains cannot be retrieved by
|
|
// NetUserGetGroups but can be fetched by authz functions.
|
|
//
|
|
|
|
xpCSid = new CSid(szAccountName);
|
|
|
|
AUTHZ_RESOURCE_MANAGER_HANDLE hAuthz;
|
|
|
|
if (!AuthzInitializeResourceManager(NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&hAuthz)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - AuthzInitializeResourceManager failed. Error - %d", GetLastError());
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
hr = ExpandGroup(xpRsopToken, hAuthz, xpCSid);
|
|
if (FAILED(hr)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - ExpandGrp failed for user. Error - 0x%x", hr);
|
|
AuthzFreeResourceManager(hAuthz);
|
|
return hr;
|
|
}
|
|
|
|
AuthzFreeResourceManager(hAuthz);
|
|
// xpCSid will be freed automatically.
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Otherwise, we add only those groups named in the SAFERARRAY.
|
|
//
|
|
|
|
else
|
|
{
|
|
BSTR* pbstr;
|
|
AUTHZ_RESOURCE_MANAGER_HANDLE hAuthz;
|
|
|
|
if (!AuthzInitializeResourceManager(NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&hAuthz)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - AuthzInitializeResourceManager failed. Error - %d", GetLastError());
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
|
|
// Get a pointer to the elements of the array.
|
|
hr = SafeArrayAccessData(psaUserSecurityGroups, (void**)&pbstr);
|
|
if(FAILED(hr))
|
|
{
|
|
AuthzFreeResourceManager(hAuthz);
|
|
return hr;
|
|
}
|
|
|
|
int count = psaUserSecurityGroups->rgsabound[0].cElements;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
xpCSid = new CSid(pbstr[i]);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
AuthzFreeResourceManager(hAuthz);
|
|
SafeArrayUnaccessData(psaUserSecurityGroups);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!xpCSid->IsValid())
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - %s is invalid", pbstr[i]);
|
|
AuthzFreeResourceManager(hAuthz);
|
|
SafeArrayUnaccessData(psaUserSecurityGroups);
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME);
|
|
}
|
|
|
|
// WellKnownGroups cannot be expanded ...
|
|
if ( xpCSid->SidType() != SidTypeWellKnownGroup )
|
|
{
|
|
hr = ExpandGroup(xpRsopToken, hAuthz, xpCSid);
|
|
if (FAILED(hr)) {
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopCreateToken - ExpandGrp failed. Error - 0x%x", hr);
|
|
AuthzFreeResourceManager(hAuthz);
|
|
SafeArrayUnaccessData(psaUserSecurityGroups);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
hr = xpRsopToken->AddSid(xpCSid);
|
|
if(FAILED(hr))
|
|
{
|
|
AuthzFreeResourceManager(hAuthz);
|
|
SafeArrayUnaccessData(psaUserSecurityGroups);
|
|
return hr;
|
|
}
|
|
|
|
xpCSid.Acquire();
|
|
|
|
}
|
|
|
|
AuthzFreeResourceManager(hAuthz);
|
|
SafeArrayUnaccessData(psaUserSecurityGroups);
|
|
|
|
|
|
}
|
|
|
|
hr = AddSpecialGroups(xpRsopToken);
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
*ppRsopToken = xpRsopToken;
|
|
|
|
xpRsopToken.Acquire();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: RsopDeleteToken
|
|
//
|
|
// Description: Destroys a pseudo-token previously created by any of the overloaded
|
|
// forms of RSOPCreateRsopToken
|
|
//
|
|
// Parameters: - pRsopToken: Pointer to a valid PRSOPTOKEN
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT RsopDeleteToken(PRSOPTOKEN pRsopToken)
|
|
{
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
delete pToken;
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: GetAceSid
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 10/19/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
PISID GetAceSid(PACE_HEADER pAceHeader)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - Entering.");
|
|
|
|
|
|
//
|
|
// Check for invalid argument
|
|
//
|
|
|
|
if(!pAceHeader)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"GetAceSid - Invalid parameter: pAceHeader is NULL");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - Leaving.");
|
|
return NULL;
|
|
}
|
|
|
|
PISID pSid = NULL;
|
|
|
|
PACCESS_ALLOWED_ACE pACCESS_ALLOWED_ACE;
|
|
PACCESS_ALLOWED_OBJECT_ACE pACCESS_ALLOWED_OBJECT_ACE;
|
|
PACCESS_DENIED_ACE pACCESS_DENIED_ACE;
|
|
PACCESS_DENIED_OBJECT_ACE pACCESS_DENIED_OBJECT_ACE;
|
|
|
|
//
|
|
// Cast the ACE header to the appropriate ACE type based on the 'Acetype' member of the
|
|
// ACE header.
|
|
//
|
|
|
|
switch(pAceHeader->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - ACE type: ACCESS_ALLOWED_ACE_TYPE");
|
|
pACCESS_ALLOWED_ACE = reinterpret_cast<PACCESS_ALLOWED_ACE>(pAceHeader);
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_ALLOWED_ACE->SidStart));
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - ACE type: ACCESS_ALLOWED_OBJECT_ACE_TYPE");
|
|
pACCESS_ALLOWED_OBJECT_ACE = reinterpret_cast<PACCESS_ALLOWED_OBJECT_ACE>(pAceHeader);
|
|
|
|
if( (pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT) &&
|
|
(pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT))
|
|
{
|
|
//
|
|
// If both ACE_OBJECT_TYPE_PRESENT and ACE_INHERITED_OBJECT_TYPE_PRESENT are set in
|
|
// the ACE flags, the SID starts at the offset specified by 'SidStart'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_ALLOWED_OBJECT_ACE->SidStart));
|
|
}
|
|
else if((pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT) ||
|
|
(pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT))
|
|
{
|
|
//
|
|
// If either ACE_OBJECT_TYPE_PRESENT or ACE_INHERITED_OBJECT_TYPE_PRESENT is set in
|
|
// the ACE flags, the SID starts at the offset specified by 'InheritedObjectType'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_ALLOWED_OBJECT_ACE->InheritedObjectType));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If neither ACE_OBJECT_TYPE_PRESENT nor ACE_INHERITED_OBJECT_TYPE_PRESENT is set in
|
|
// the ACE flags, the SID starts at the offset specified by 'ObjectType'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_ALLOWED_OBJECT_ACE->ObjectType));
|
|
}
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - ACE type: ACCESS_DENIED_ACE_TYPE");
|
|
pACCESS_DENIED_ACE = reinterpret_cast<PACCESS_DENIED_ACE>(pAceHeader);
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_DENIED_ACE->SidStart));
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - ACE type: ACCESS_DENIED_OBJECT_ACE_TYPE");
|
|
pACCESS_DENIED_OBJECT_ACE = reinterpret_cast<PACCESS_DENIED_OBJECT_ACE>(pAceHeader);
|
|
if( (pACCESS_DENIED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT) &&
|
|
(pACCESS_DENIED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT))
|
|
{
|
|
//
|
|
// If both ACE_OBJECT_TYPE_PRESENT and ACE_INHERITED_OBJECT_TYPE_PRESENT are set in
|
|
// the ACE flags, the SID starts at the offset specified by 'SidStart'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_DENIED_OBJECT_ACE->SidStart));
|
|
}
|
|
else if((pACCESS_DENIED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT) ||
|
|
(pACCESS_DENIED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT))
|
|
{
|
|
//
|
|
// If either ACE_OBJECT_TYPE_PRESENT or ACE_INHERITED_OBJECT_TYPE_PRESENT is set in
|
|
// the ACE flags, the SID starts at the offset specified by 'InheritedObjectType'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_DENIED_OBJECT_ACE->InheritedObjectType));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If neither ACE_OBJECT_TYPE_PRESENT nor ACE_INHERITED_OBJECT_TYPE_PRESENT is set in
|
|
// the ACE flags, the SID starts at the offset specified by 'ObjectType'.
|
|
//
|
|
|
|
pSid = reinterpret_cast<PISID>(&(pACCESS_DENIED_OBJECT_ACE->ObjectType));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"GetAceSid - Unexpected ACE type found. Type: 0x%08X", pAceHeader->AceType);
|
|
break;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"GetAceSid - Leaving.");
|
|
|
|
return pSid;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CheckAceApplies
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/8/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT CheckAceApplies(PACE_HEADER pAceHeader, PRSOPTOKEN pRsopToken, bool* pbAceApplies)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - Entering.");
|
|
|
|
//
|
|
// Get the SID from the ACE associated with this Ace Header.
|
|
//
|
|
|
|
PISID pSid = GetAceSid(pAceHeader);
|
|
if(!pSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"CheckAceApplies - GetAceSid failed.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - Leaving.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pbAceApplies = false;
|
|
|
|
//
|
|
// Compare the SID from the ACE with all the SIDs in the RsopToken.
|
|
//
|
|
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
for(CTLink<CSid>* pLink = pToken->m_pSidsHead; pLink; pLink = pLink->m_pNext)
|
|
{
|
|
//
|
|
// If one of the SIDs in the RsopToken matches
|
|
// the SID in the ACE, this ACE applies.
|
|
//
|
|
|
|
if(EqualSid(pSid, pLink->m_pData->GetSidPtr()))
|
|
{
|
|
*pbAceApplies = true;
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - One of the SIDs in the RsopToken matches the SID in the ACE. The ACE applies.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - Leaving.");
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - None of the SIDs in the RsopToken matches the SID in the ACE. The ACE does not apply.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"CheckAceApplies - Leaving.");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
const DWORD MAX_PERM_BITS=25;
|
|
|
|
//******************************************************************************
|
|
enum EPermission{ PERMISSION_DENIED, PERMISSION_ALLOWED, PERMISSION_NOT_SET};
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Class: CSubObjectPerm
|
|
//
|
|
// Description:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
class CSubObjectPerm
|
|
{
|
|
private:
|
|
|
|
CTLink<GUID>* m_pGuidsHead;
|
|
CTLink<GUID>* m_pGuidsTail;
|
|
|
|
EPermission permissionBits[MAX_PERM_BITS];
|
|
|
|
public:
|
|
|
|
CSubObjectPerm();
|
|
~CSubObjectPerm();
|
|
|
|
HRESULT AddGuid(GUID* pGuid);
|
|
|
|
void ProcessAceMask(DWORD dwMask, EPermission permission, GUID* pGuid);
|
|
DWORD GetAccumulatedPermissions();
|
|
bool AnyDenied();
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::CSubObjectPerm
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CSubObjectPerm::CSubObjectPerm() : m_pGuidsHead(NULL), m_pGuidsTail(NULL)
|
|
{
|
|
for (int i = 0; i < MAX_PERM_BITS; i++)
|
|
{
|
|
permissionBits[i] = PERMISSION_NOT_SET;
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::~CSubObjectPerm
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CSubObjectPerm::~CSubObjectPerm()
|
|
{
|
|
CTLink<GUID>* pLinkIterator = m_pGuidsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
CTLink<GUID>* pLinkToDelete = pLinkIterator;
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
delete pLinkToDelete;
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::AddGuid
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT CSubObjectPerm::AddGuid(GUID* pGuid)
|
|
{
|
|
CTLink<GUID>* pLink = new CTLink<GUID>(pGuid);
|
|
if(!pLink)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!m_pGuidsHead)
|
|
{
|
|
m_pGuidsHead = pLink;
|
|
}
|
|
else
|
|
{
|
|
m_pGuidsTail->m_pNext = pLink;
|
|
}
|
|
|
|
m_pGuidsTail = pLink;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::ProcessAceMask
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void CSubObjectPerm::ProcessAceMask(DWORD dwMask, EPermission permission, GUID* pGuid)
|
|
{
|
|
bool bAceApplies = false;
|
|
|
|
if(!pGuid)
|
|
{
|
|
bAceApplies = true;
|
|
}
|
|
|
|
else if(pGuid && m_pGuidsHead)
|
|
{
|
|
CTLink<GUID>* pLinkIterator = m_pGuidsHead;
|
|
|
|
while(pLinkIterator)
|
|
{
|
|
if(*(pLinkIterator->m_pData) == *pGuid)
|
|
{
|
|
bAceApplies = true;
|
|
break;
|
|
}
|
|
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
}
|
|
|
|
if(bAceApplies)
|
|
{
|
|
DWORD dwTemp = 0x00000001;
|
|
|
|
for(int i = 0; i < MAX_PERM_BITS; i++)
|
|
{
|
|
if((dwMask & dwTemp) && (permissionBits[i] == PERMISSION_NOT_SET))
|
|
{
|
|
permissionBits[i] = permission;
|
|
}
|
|
|
|
dwTemp <<= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::AccumulatedPermissions
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
DWORD CSubObjectPerm::GetAccumulatedPermissions()
|
|
{
|
|
DWORD dwAccumulatedPermissions = 0;
|
|
|
|
for(int i = MAX_PERM_BITS - 1; i >= 0; i--)
|
|
{
|
|
dwAccumulatedPermissions <<= 1;
|
|
if(permissionBits[i] == PERMISSION_ALLOWED)
|
|
{
|
|
dwAccumulatedPermissions |= 0x00000001;
|
|
}
|
|
}
|
|
|
|
return dwAccumulatedPermissions;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CSubObjectPerm::AnyDenied
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 11/09/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
bool CSubObjectPerm::AnyDenied()
|
|
{
|
|
for(int i = 0; i < MAX_PERM_BITS; i++)
|
|
{
|
|
if(permissionBits[i] == PERMISSION_DENIED)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Struct: CDSObject
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// History: 10/25/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
struct CDSObject
|
|
{
|
|
DWORD m_dwLevel;
|
|
GUID* m_pGuid;
|
|
|
|
CDSObject() : m_pGuid(NULL){}
|
|
~CDSObject()
|
|
{
|
|
delete m_pGuid;
|
|
}
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Class: CAccumulatedPermissions
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// History: 10/25/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
class CAccumulatedPermissions
|
|
{
|
|
CTLink<CSubObjectPerm>* m_pSubObjectsHead;
|
|
CTLink<CSubObjectPerm>* m_pSubObjectsTail;
|
|
|
|
CTLink<CDSObject>* m_pDSObjectsHead;
|
|
CTLink<CDSObject>* m_pDSObjectsTail;
|
|
|
|
bool m_bInitialized;
|
|
|
|
public:
|
|
CAccumulatedPermissions(POBJECT_TYPE_LIST pObjectTypeList,
|
|
DWORD ObjectTypeListLength);
|
|
~CAccumulatedPermissions();
|
|
void ProcessAceMask(DWORD dwMask, EPermission permission, GUID* pGuid);
|
|
DWORD GetAccumulatedPermissions();
|
|
bool AnyDenied();
|
|
|
|
bool Initialized(){return m_bInitialized;}
|
|
};
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CAccumulatedPermissions::CAccumulatedPermissions
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 10/25/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CAccumulatedPermissions::CAccumulatedPermissions( POBJECT_TYPE_LIST pObjectTypeList,
|
|
DWORD ObjectTypeListLength) :
|
|
m_pSubObjectsHead(NULL),
|
|
m_pSubObjectsTail(NULL),
|
|
m_bInitialized(false),
|
|
m_pDSObjectsHead(NULL),
|
|
m_pDSObjectsTail(NULL)
|
|
{
|
|
|
|
if(!pObjectTypeList || ObjectTypeListLength == 0)
|
|
{
|
|
XPtrST<CSubObjectPerm>xpSubObjectPerm = new CSubObjectPerm;
|
|
if(!xpSubObjectPerm)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_pSubObjectsHead = new CTLink<CSubObjectPerm>(xpSubObjectPerm);
|
|
if(!m_pSubObjectsHead)
|
|
{
|
|
return;
|
|
}
|
|
xpSubObjectPerm.Acquire();
|
|
|
|
m_pSubObjectsTail = m_pSubObjectsHead;
|
|
|
|
m_bInitialized = true;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
DWORD dwCurrentLevel;
|
|
|
|
for(DWORD i = 0; i < ObjectTypeListLength; i++)
|
|
{
|
|
if( i==0 )
|
|
{
|
|
//
|
|
// This assumes that the first element in the list of
|
|
// OBJECT_TYPEs pointed to by pObjectTypeList is at
|
|
// level ACCESS_OBJECT_GUID.
|
|
//
|
|
|
|
dwCurrentLevel = pObjectTypeList[i].Level;
|
|
|
|
XPtrST<CDSObject>xpDSObject = new CDSObject;
|
|
if(!xpDSObject)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XPtrST<GUID>xpGuid = new GUID(*(pObjectTypeList[i].ObjectType));
|
|
if(!xpGuid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_pDSObjectsHead = new CTLink<CDSObject>(xpDSObject);
|
|
if(!m_pDSObjectsHead)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xpDSObject.Acquire();
|
|
|
|
m_pDSObjectsHead->m_pData->m_pGuid = xpGuid.Acquire();
|
|
|
|
m_pDSObjectsHead->m_pData->m_dwLevel = pObjectTypeList[i].Level;
|
|
|
|
m_pDSObjectsTail = m_pDSObjectsHead;
|
|
|
|
continue;
|
|
}
|
|
|
|
else if(pObjectTypeList[i].Level > dwCurrentLevel)
|
|
{
|
|
dwCurrentLevel = pObjectTypeList[i].Level;
|
|
|
|
XPtrST<CDSObject> xpDSObject = new CDSObject;
|
|
if(!xpDSObject)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XPtrST<GUID>xpGuid = new GUID(*(pObjectTypeList[i].ObjectType));
|
|
if(!xpGuid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CTLink<CDSObject>* pDSObjectLink = new CTLink<CDSObject>(xpDSObject);
|
|
if(!pDSObjectLink)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xpDSObject.Acquire();
|
|
|
|
pDSObjectLink->m_pData->m_pGuid = xpGuid.Acquire();
|
|
pDSObjectLink->m_pData->m_dwLevel = pObjectTypeList[i].Level;
|
|
|
|
pDSObjectLink->m_pPrev = m_pDSObjectsTail;
|
|
m_pDSObjectsTail->m_pNext = pDSObjectLink;
|
|
m_pDSObjectsTail = pDSObjectLink;
|
|
}
|
|
|
|
else
|
|
{
|
|
XPtrST<CSubObjectPerm>xpSubObjectPerm = new CSubObjectPerm;
|
|
if(!xpSubObjectPerm)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CTLink<CSubObjectPerm>* pSubObjectLink = new CTLink<CSubObjectPerm>(xpSubObjectPerm);
|
|
if(!pSubObjectLink)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xpSubObjectPerm.Acquire();
|
|
|
|
|
|
CTLink<CDSObject>* pLinkIterator = m_pDSObjectsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
XPtrST<GUID>xpGuid = new GUID(*(pLinkIterator->m_pData->m_pGuid));
|
|
if(!xpGuid)
|
|
{
|
|
delete pSubObjectLink;
|
|
return;
|
|
}
|
|
|
|
if(FAILED(pSubObjectLink->m_pData->AddGuid(xpGuid)))
|
|
{
|
|
delete pSubObjectLink;
|
|
return;
|
|
}
|
|
|
|
xpGuid.Acquire();
|
|
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
|
|
if(!m_pSubObjectsHead)
|
|
{
|
|
m_pSubObjectsHead = pSubObjectLink;
|
|
}
|
|
else
|
|
{
|
|
m_pSubObjectsTail->m_pNext = pSubObjectLink;
|
|
}
|
|
m_pSubObjectsTail = pSubObjectLink;
|
|
|
|
|
|
pLinkIterator = m_pDSObjectsTail;
|
|
|
|
if(pLinkIterator)
|
|
{
|
|
while(pLinkIterator->m_pData->m_dwLevel >= pObjectTypeList[i].Level)
|
|
{
|
|
CTLink<CDSObject>* pLinkToDelete = pLinkIterator;
|
|
pLinkIterator = pLinkIterator->m_pPrev;
|
|
delete pLinkToDelete;
|
|
m_pDSObjectsTail = pLinkIterator;
|
|
if(m_pDSObjectsTail)
|
|
{
|
|
m_pDSObjectsTail->m_pNext = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
XPtrST<CDSObject>xpDSObject = new CDSObject;
|
|
if(!xpDSObject)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XPtrST<GUID>xpGuid = new GUID(*(pObjectTypeList[i].ObjectType));
|
|
if(!xpGuid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CTLink<CDSObject>* pLink = new CTLink<CDSObject>(xpDSObject);
|
|
if(!pLink)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xpDSObject.Acquire();
|
|
|
|
pLink->m_pData->m_pGuid = xpGuid.Acquire();
|
|
pLink->m_pData->m_dwLevel = pObjectTypeList[i].Level;
|
|
|
|
pLink->m_pPrev = m_pDSObjectsTail;
|
|
m_pDSObjectsTail->m_pNext = pLink;
|
|
m_pDSObjectsTail = pLink;
|
|
}
|
|
}
|
|
|
|
CTLink<CDSObject>* pLinkIterator = m_pDSObjectsHead;
|
|
|
|
if(pLinkIterator)
|
|
{
|
|
XPtrST<CSubObjectPerm>xpSubObject = new CSubObjectPerm;
|
|
if(!xpSubObject)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CTLink<CSubObjectPerm>* pSubObjectLink = new CTLink<CSubObjectPerm>(xpSubObject);
|
|
if(!pSubObjectLink)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xpSubObject.Acquire();
|
|
|
|
while(pLinkIterator)
|
|
{
|
|
XPtrST<GUID>xpGuid = new GUID(*(pLinkIterator->m_pData->m_pGuid));
|
|
if(!xpGuid)
|
|
{
|
|
delete pSubObjectLink;
|
|
return;
|
|
}
|
|
|
|
if(FAILED(pSubObjectLink->m_pData->AddGuid(xpGuid)))
|
|
{
|
|
delete pSubObjectLink;
|
|
return;
|
|
}
|
|
|
|
xpGuid.Acquire();
|
|
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
|
|
if(!m_pSubObjectsHead)
|
|
{
|
|
m_pSubObjectsHead = pSubObjectLink;
|
|
}
|
|
else
|
|
{
|
|
m_pSubObjectsTail->m_pNext = pSubObjectLink;
|
|
}
|
|
m_pSubObjectsTail = pSubObjectLink;
|
|
}
|
|
|
|
pLinkIterator = m_pDSObjectsHead;
|
|
|
|
while(pLinkIterator)
|
|
{
|
|
CTLink<CDSObject>* pLinkToDelete = pLinkIterator;
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
delete pLinkToDelete;
|
|
}
|
|
|
|
m_pDSObjectsHead = m_pDSObjectsTail = NULL;
|
|
|
|
m_bInitialized = true;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CAccumulatedPermissions::~CAccumulatedPermissions
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 10/25/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
CAccumulatedPermissions::~CAccumulatedPermissions()
|
|
{
|
|
CTLink<CSubObjectPerm>* pSubObjectLinkIterator = m_pSubObjectsHead;
|
|
while(pSubObjectLinkIterator)
|
|
{
|
|
CTLink<CSubObjectPerm>* pSubObjectLinkToDelete = pSubObjectLinkIterator;
|
|
pSubObjectLinkIterator = pSubObjectLinkIterator->m_pNext;
|
|
delete pSubObjectLinkToDelete;
|
|
}
|
|
|
|
CTLink<CDSObject>* pDSObjectLinkIterator = m_pDSObjectsHead;
|
|
|
|
while(pDSObjectLinkIterator)
|
|
{
|
|
CTLink<CDSObject>* pDSObjectLinkToDelete = pDSObjectLinkIterator;
|
|
pDSObjectLinkIterator = pDSObjectLinkIterator->m_pNext;
|
|
delete pDSObjectLinkToDelete;
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CAccumulatedPermissions::ProcessAceMask
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 8/8/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void CAccumulatedPermissions::ProcessAceMask(DWORD dwMask, EPermission permission, GUID* pGuid)
|
|
{
|
|
CTLink<CSubObjectPerm>* pLinkIterator = m_pSubObjectsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
pLinkIterator->m_pData->ProcessAceMask(dwMask, permission, pGuid);
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CAccumulatedPermissions::AccumulatedPermissions
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 8/8/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
DWORD CAccumulatedPermissions::GetAccumulatedPermissions()
|
|
{
|
|
|
|
DWORD dwAccumulatedPermissions = 0x01FFFFFF;
|
|
|
|
CTLink<CSubObjectPerm>* pLinkIterator = m_pSubObjectsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
dwAccumulatedPermissions &= pLinkIterator->m_pData->GetAccumulatedPermissions();
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
|
|
return dwAccumulatedPermissions;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: CAccumulatedPermissions::AnyDenied
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
// History: 8/8/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
bool CAccumulatedPermissions::AnyDenied()
|
|
{
|
|
CTLink<CSubObjectPerm>* pLinkIterator = m_pSubObjectsHead;
|
|
while(pLinkIterator)
|
|
{
|
|
if(pLinkIterator->m_pData->AnyDenied())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
pLinkIterator = pLinkIterator->m_pNext;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: LogGuid
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: void
|
|
//
|
|
// History: 10/26/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void LogGuid(GUID& guid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogGuid - Entering.");
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogGuid - {0x%08x 0x%04x 0x%04x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x}",
|
|
guid.Data1,
|
|
guid.Data2,
|
|
guid.Data3,
|
|
guid.Data4[0],
|
|
guid.Data4[1],
|
|
guid.Data4[2],
|
|
guid.Data4[3],
|
|
guid.Data4[4],
|
|
guid.Data4[5],
|
|
guid.Data4[6],
|
|
guid.Data4[7]);
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogGuid - (%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x)",
|
|
guid.Data1,
|
|
guid.Data2,
|
|
guid.Data3,
|
|
guid.Data4[0],
|
|
guid.Data4[1],
|
|
guid.Data4[2],
|
|
guid.Data4[3],
|
|
guid.Data4[4],
|
|
guid.Data4[5],
|
|
guid.Data4[6],
|
|
guid.Data4[7]);
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogGuid - Leaving.");
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: LogSid
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: void
|
|
//
|
|
// History: 10/26/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void LogSid(PSID pSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Entering.");
|
|
|
|
XPtrST<CSid>xpCSid = new CSid(pSid);
|
|
|
|
if(!xpCSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"LogSid - Call to operator new failed.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Leaving.");
|
|
return;
|
|
}
|
|
|
|
if(!(xpCSid->IsValid()))
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"LogSid - call to CSid::IsValid returned false.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Leaving.");
|
|
return;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid string: %s.", xpCSid->SidString());
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid User: %s.", xpCSid->User());
|
|
|
|
if(xpCSid->SidType() == SidTypeUser)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeUser.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeGroup)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeGroup.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeDomain)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeDomain.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeAlias)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeAlias.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeWellKnownGroup)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeWellKnownGroup.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeDeletedAccount)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeDeletedAccount.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeInvalid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeInvalid.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeUnknown)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeUnknown.");
|
|
}
|
|
else if(xpCSid->SidType() == SidTypeComputer)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid type: SidTypeComputer.");
|
|
}
|
|
else
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"LogSid - Sid type: UNKNOWN SID type.");
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid Domain: %s.", xpCSid->Domain());
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Sid Computer: %s.", xpCSid->Computer());
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogSid - Leaving.");
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: LogAce
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: void
|
|
//
|
|
// History: 10/26/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
void LogAce(PACE_HEADER pAceHeader)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Entering.");
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - AceType = 0x%08X.", pAceHeader->AceType);
|
|
|
|
|
|
PACCESS_ALLOWED_ACE pACCESS_ALLOWED_ACE = NULL;
|
|
PACCESS_ALLOWED_OBJECT_ACE pACCESS_ALLOWED_OBJECT_ACE = NULL;
|
|
|
|
PACCESS_DENIED_ACE pACCESS_DENIED_ACE = NULL;
|
|
PACCESS_DENIED_OBJECT_ACE pACCESS_DENIED_OBJECT_ACE = NULL;
|
|
|
|
PSYSTEM_AUDIT_ACE pSYSTEM_AUDIT_ACE = NULL;
|
|
PSYSTEM_AUDIT_OBJECT_ACE pSYSTEM_AUDIT_OBJECT_ACE = NULL;
|
|
|
|
PSYSTEM_ALARM_ACE pSYSTEM_ALARM_ACE = NULL;
|
|
PSYSTEM_ALARM_OBJECT_ACE pSYSTEM_ALARM_OBJECT_ACE = NULL;
|
|
|
|
switch(pAceHeader->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: ACCESS_ALLOWED_ACE_TYPE");
|
|
pACCESS_ALLOWED_ACE = reinterpret_cast<PACCESS_ALLOWED_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pACCESS_ALLOWED_ACE->Mask);
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: ACCESS_ALLOWED_OBJECT_ACE_TYPE");
|
|
pACCESS_ALLOWED_OBJECT_ACE = reinterpret_cast<PACCESS_ALLOWED_OBJECT_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pACCESS_ALLOWED_OBJECT_ACE->Mask);
|
|
|
|
if(pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pACCESS_ALLOWED_OBJECT_ACE->ObjectType);
|
|
}
|
|
|
|
if(pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_INHERITED_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pACCESS_ALLOWED_OBJECT_ACE->InheritedObjectType);
|
|
}
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: ACCESS_DENIED_ACE_TYPE");
|
|
pACCESS_DENIED_ACE = reinterpret_cast<PACCESS_DENIED_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pACCESS_DENIED_ACE->Mask);
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: ACCESS_DENIED_OBJECT_ACE_TYPE");
|
|
pACCESS_DENIED_OBJECT_ACE = reinterpret_cast<PACCESS_DENIED_OBJECT_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pACCESS_DENIED_OBJECT_ACE->Mask);
|
|
|
|
if(pACCESS_DENIED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pACCESS_DENIED_OBJECT_ACE->ObjectType);
|
|
}
|
|
|
|
if(pACCESS_DENIED_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_INHERITED_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pACCESS_DENIED_OBJECT_ACE->InheritedObjectType);
|
|
}
|
|
break;
|
|
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: SYSTEM_AUDIT_ACE_TYPE");
|
|
pSYSTEM_AUDIT_ACE = reinterpret_cast<PSYSTEM_AUDIT_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pSYSTEM_AUDIT_ACE->Mask);
|
|
break;
|
|
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: SYSTEM_AUDIT_OBJECT_ACE_TYPE");
|
|
pSYSTEM_AUDIT_OBJECT_ACE = reinterpret_cast<PSYSTEM_AUDIT_OBJECT_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pSYSTEM_AUDIT_OBJECT_ACE->Mask);
|
|
|
|
if(pSYSTEM_AUDIT_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pSYSTEM_AUDIT_OBJECT_ACE->ObjectType);
|
|
}
|
|
|
|
if(pSYSTEM_AUDIT_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_INHERITED_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pSYSTEM_AUDIT_OBJECT_ACE->InheritedObjectType);
|
|
}
|
|
break;
|
|
|
|
case SYSTEM_ALARM_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: SYSTEM_ALARM_ACE_TYPE");
|
|
pSYSTEM_ALARM_ACE = reinterpret_cast<PSYSTEM_ALARM_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pSYSTEM_ALARM_ACE->Mask);
|
|
break;
|
|
|
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE type: SYSTEM_ALARM_OBJECT_ACE_TYPE");
|
|
pSYSTEM_ALARM_OBJECT_ACE = reinterpret_cast<PSYSTEM_ALARM_OBJECT_ACE>(pAceHeader);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - ACE Mask: 0x%08X", pSYSTEM_ALARM_OBJECT_ACE->Mask);
|
|
|
|
if(pSYSTEM_ALARM_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pSYSTEM_ALARM_OBJECT_ACE->ObjectType);
|
|
}
|
|
|
|
if(pSYSTEM_ALARM_OBJECT_ACE->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Flag is on: ACE_INHERITED_OBJECT_TYPE_PRESENT.");
|
|
LogGuid(pSYSTEM_ALARM_OBJECT_ACE->InheritedObjectType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"LogAce - ACE type: UNKNOWN ACE type.");
|
|
break;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - AceFlags = 0x%08X.", pAceHeader->AceFlags);
|
|
|
|
if(pAceHeader->AceFlags & OBJECT_INHERIT_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: OBJECT_INHERIT_ACE.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & CONTAINER_INHERIT_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: CONTAINER_INHERIT_ACE.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & NO_PROPAGATE_INHERIT_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: NO_PROPAGATE_INHERIT_ACE.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & INHERIT_ONLY_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: INHERIT_ONLY_ACE.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & INHERITED_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: INHERITED_ACE.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: SUCCESSFUL_ACCESS_ACE_FLAG.");
|
|
}
|
|
|
|
if(pAceHeader->AceFlags & FAILED_ACCESS_ACE_FLAG)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - The Following ACE header flag is on: FAILED_ACCESS_ACE_FLAG.");
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - AceSize = 0x%08X.", pAceHeader->AceSize);
|
|
|
|
|
|
PISID pSid = GetAceSid(pAceHeader);
|
|
if(!pSid)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"LogAce - Call to GetAceSid failed.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Leaving.");
|
|
return;
|
|
}
|
|
|
|
LogSid(pSid);
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"LogAce - Leaving.");
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: ProcessAce
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
// History: 8/8/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT ProcessAce( PACE_HEADER pAceHeader,
|
|
PRSOPTOKEN pRsopToken,
|
|
POBJECT_TYPE_LIST pObjectTypeList,
|
|
DWORD ObjectTypeListLength,
|
|
DWORD dwDesiredAccessMask,
|
|
CAccumulatedPermissions& accumulatedPermissions,
|
|
bool* pbAccessExplicitlyDenied)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Entering.");
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
|
|
if( !pAceHeader || !pRsopToken ||
|
|
(ObjectTypeListLength && !pObjectTypeList) ||
|
|
!pbAccessExplicitlyDenied)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ProcessAce - Invalid argument(s).");
|
|
return E_FAIL;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Desired Access Mask: 0x%08X.", dwDesiredAccessMask);
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Desired Access Mask == MAXIMUM_ALLOWED.");
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Accumulated Permissions BEFORE Processing Ace: 0x%08X.", accumulatedPermissions.GetAccumulatedPermissions());
|
|
|
|
|
|
//
|
|
// Log ACE information
|
|
//
|
|
|
|
LogAce(pAceHeader);
|
|
|
|
*pbAccessExplicitlyDenied = false;
|
|
|
|
//
|
|
// ACEs with INHERIT_ONLY_ACE flag do no control access to the current object.
|
|
// Therefore, we ignore them.
|
|
//
|
|
|
|
if(pAceHeader->AceFlags & INHERIT_ONLY_ACE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Found ACE with INHERIT_ONLY_ACE flag. Ace does not apply.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// If this ACE does not reference any of the SIDs contained in the RsopToken,
|
|
// we ignore it.
|
|
//
|
|
|
|
bool bAceApplies;
|
|
HRESULT hr = CheckAceApplies(pAceHeader, pRsopToken, &bAceApplies);
|
|
if(FAILED(hr))
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ProcessAce - CheckAceApplies failed. Return code: 0x%08X", hr);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Leaving.");
|
|
return hr;
|
|
}
|
|
|
|
if(!bAceApplies)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE does not apply.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE aplies.");
|
|
|
|
PACCESS_ALLOWED_ACE pACCESS_ALLOWED_ACE;
|
|
PACCESS_ALLOWED_OBJECT_ACE pACCESS_ALLOWED_OBJECT_ACE;
|
|
PACCESS_DENIED_ACE pACCESS_DENIED_ACE;
|
|
PACCESS_DENIED_OBJECT_ACE pACCESS_DENIED_OBJECT_ACE;
|
|
|
|
DWORD i;
|
|
DWORD dwMask;
|
|
switch(pAceHeader->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE type: ACCESS_ALLOWED_ACE_TYPE");
|
|
pACCESS_ALLOWED_ACE = reinterpret_cast<PACCESS_ALLOWED_ACE>(pAceHeader);
|
|
|
|
//
|
|
// If the requested access is MAXIMUM_ALLOWED, consider all bits in the Mask
|
|
// controlled by this ACE.
|
|
// Otherwise, consider only those bits that are also specified in the
|
|
// desired access mask.
|
|
//
|
|
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
dwMask = pACCESS_ALLOWED_ACE->Mask;
|
|
}
|
|
else
|
|
{
|
|
dwMask = dwDesiredAccessMask & pACCESS_ALLOWED_ACE->Mask;
|
|
}
|
|
|
|
accumulatedPermissions.ProcessAceMask( dwMask,
|
|
PERMISSION_ALLOWED,
|
|
NULL);
|
|
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE type: ACCESS_ALLOWED_OBJECT_ACE_TYPE");
|
|
pACCESS_ALLOWED_OBJECT_ACE = reinterpret_cast<PACCESS_ALLOWED_OBJECT_ACE>(pAceHeader);
|
|
|
|
|
|
//
|
|
// We have chosen to process only those object ACEs that have
|
|
// the flag ACE_OBJECT_TYPE_PRESENT set.
|
|
//
|
|
|
|
if(pACCESS_ALLOWED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
|
|
|
|
//
|
|
// Notice that if this function is invoked with no
|
|
// ObjectTypeList, object ACEs are disregarded.
|
|
//
|
|
|
|
for(i = 0; i < ObjectTypeListLength; i++)
|
|
{
|
|
POBJECT_TYPE_LIST pObjectType = &(pObjectTypeList[i]);
|
|
if(*(pObjectType->ObjectType) == pACCESS_ALLOWED_OBJECT_ACE->ObjectType)
|
|
{
|
|
//
|
|
// If the requested access is MAXIMUM_ALLOWED, consider all bits in the Mask
|
|
// controlled by this ACE.
|
|
// Otherwise, consider only those bits that are also specified in the
|
|
// desired access mask.
|
|
//
|
|
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
dwMask = pACCESS_ALLOWED_OBJECT_ACE->Mask;
|
|
}
|
|
else
|
|
{
|
|
dwMask = dwDesiredAccessMask & pACCESS_ALLOWED_OBJECT_ACE->Mask;
|
|
}
|
|
|
|
accumulatedPermissions.ProcessAceMask( dwMask,
|
|
PERMISSION_ALLOWED,
|
|
&(pACCESS_ALLOWED_OBJECT_ACE->ObjectType));
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE type: ACCESS_DENIED_ACE_TYPE");
|
|
pACCESS_DENIED_ACE = reinterpret_cast<PACCESS_DENIED_ACE>(pAceHeader);
|
|
|
|
|
|
//
|
|
// If the requested access is MAXIMUM_ALLOWED, consider all bits in the Mask
|
|
// controlled by this ACE.
|
|
// Otherwise, consider only those bits that are also specified in the
|
|
// desired access mask.
|
|
//
|
|
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
dwMask = pACCESS_DENIED_ACE->Mask;
|
|
}
|
|
else
|
|
{
|
|
dwMask = dwDesiredAccessMask & pACCESS_DENIED_ACE->Mask;
|
|
}
|
|
|
|
accumulatedPermissions.ProcessAceMask( dwMask,
|
|
PERMISSION_DENIED,
|
|
NULL);
|
|
|
|
if(dwDesiredAccessMask != MAXIMUM_ALLOWED)
|
|
{
|
|
if(accumulatedPermissions.AnyDenied())
|
|
{
|
|
*pbAccessExplicitlyDenied = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - ACE type: ACCESS_DENIED_OBJECT_ACE_TYPE");
|
|
pACCESS_DENIED_OBJECT_ACE = reinterpret_cast<PACCESS_DENIED_OBJECT_ACE>(pAceHeader);
|
|
|
|
|
|
//
|
|
// We have chosen to process only those object ACEs that have
|
|
// the flag ACE_OBJECT_TYPE_PRESENT set.
|
|
//
|
|
|
|
if(pACCESS_DENIED_OBJECT_ACE->Flags & ACE_OBJECT_TYPE_PRESENT)
|
|
{
|
|
|
|
|
|
//
|
|
// Notice that if this function is invoked with no
|
|
// ObjectTypeList, object ACEs are disregarded.
|
|
//
|
|
|
|
for(i = 0; i < ObjectTypeListLength; i++)
|
|
{
|
|
POBJECT_TYPE_LIST pObjectType = &(pObjectTypeList[i]);
|
|
if(*(pObjectType->ObjectType) == pACCESS_DENIED_OBJECT_ACE->ObjectType)
|
|
{
|
|
//
|
|
// If the requested access is MAXIMUM_ALLOWED, consider all bits in the Mask
|
|
// controlled by this ACE.
|
|
// Otherwise, consider only those bits that are also specified in the
|
|
// desired access mask.
|
|
//
|
|
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
dwMask = pACCESS_DENIED_OBJECT_ACE->Mask;
|
|
}
|
|
else
|
|
{
|
|
dwMask = dwDesiredAccessMask & pACCESS_DENIED_OBJECT_ACE->Mask;
|
|
}
|
|
|
|
accumulatedPermissions.ProcessAceMask( dwMask,
|
|
PERMISSION_DENIED,
|
|
&(pACCESS_DENIED_OBJECT_ACE->ObjectType));
|
|
|
|
if(dwDesiredAccessMask != MAXIMUM_ALLOWED)
|
|
{
|
|
if(accumulatedPermissions.AnyDenied())
|
|
{
|
|
*pbAccessExplicitlyDenied = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"ProcessAce - Unexpected ACE type found in ACE header. Type: 0x%08x", pAceHeader->AceType);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Leaving.");
|
|
return E_FAIL;
|
|
break;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Accumulated Permissions AFTER Processing Ace: 0x%08X.", accumulatedPermissions.GetAccumulatedPermissions());
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"ProcessAce - Leaving.");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: RsopAccessCheckByType
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters: - pSecurityDescriptor,
|
|
// - pPrincipalSelfSid:
|
|
// - pRsopToken:
|
|
// - dwDesiredAccessMask:
|
|
// - pObjectTypeList:
|
|
// - ObjectTypeListLength:
|
|
// - pGenericMapping:
|
|
// - pPrivilegeSet:
|
|
// - pdwPrivilegeSetLength:
|
|
// - pdwGrantedAccessMask:
|
|
// - pbAccessStatus:
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT RsopAccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
PSID pPrincipalSelfSid,
|
|
PRSOPTOKEN pRsopToken,
|
|
DWORD dwDesiredAccessMask,
|
|
POBJECT_TYPE_LIST pObjectTypeList,
|
|
DWORD ObjectTypeListLength,
|
|
PGENERIC_MAPPING pGenericMapping,
|
|
PPRIVILEGE_SET pPrivilegeSet,
|
|
LPDWORD pdwPrivilegeSetLength,
|
|
LPDWORD pdwGrantedAccessMask,
|
|
LPBOOL pbAccessStatus)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Entering.");
|
|
|
|
|
|
//
|
|
// Check arguments.
|
|
//
|
|
|
|
if( !pSecurityDescriptor |
|
|
!IsValidSecurityDescriptor(pSecurityDescriptor) |
|
|
!pRsopToken |
|
|
!pGenericMapping |
|
|
!pdwGrantedAccessMask |
|
|
!pbAccessStatus)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopAccessCheckByType - Function invoked with invalid arguments.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the DACL from the Security Descriptor
|
|
//
|
|
|
|
BOOL bDaclPresent;
|
|
PACL pDacl;
|
|
BOOL bDaclDefaulted;
|
|
if(!GetSecurityDescriptorDacl(pSecurityDescriptor, &bDaclPresent, &pDacl, &bDaclDefaulted))
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopAccessCheckByType - GetSecurityDescriptorDacl failed. GetLastError=0x%08X", dwLastError);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Map generic rights specified in dwDesiredAccessMask to standard
|
|
// and specific rights.
|
|
// This is necessary because the ACEs in the DACL specify standard
|
|
// and specific rights only.
|
|
//
|
|
|
|
if(dwDesiredAccessMask != MAXIMUM_ALLOWED)
|
|
{
|
|
MapGenericMask(&dwDesiredAccessMask, pGenericMapping);
|
|
}
|
|
|
|
|
|
//
|
|
// If no DACL is present (as indicated by bDaclPresent) in the security descriptor,
|
|
// or if it present (as indicated by bDaclPresent) but it is a NULL DACL
|
|
// the object implicitly grants all access.
|
|
//
|
|
|
|
if(!bDaclPresent || pDacl == NULL)
|
|
{
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
*pdwGrantedAccessMask = pGenericMapping->GenericAll |
|
|
pGenericMapping->GenericExecute |
|
|
pGenericMapping->GenericRead |
|
|
pGenericMapping->GenericWrite;
|
|
}
|
|
else
|
|
{
|
|
*pdwGrantedAccessMask = dwDesiredAccessMask;
|
|
}
|
|
*pbAccessStatus = TRUE;
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - No DACL present. All access is granted.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD dwAceCount = pDacl->AceCount;
|
|
|
|
|
|
//
|
|
// If the DACL is present but it is empty,
|
|
// the object implicitly denies access to everyone.
|
|
//
|
|
|
|
if(!dwAceCount)
|
|
{
|
|
*pdwGrantedAccessMask = 0;
|
|
*pbAccessStatus = FALSE;
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - The DACL is present but it is empty. All access is denied.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// At this point we have an array of ACES structures
|
|
//
|
|
// If the desired access is different from MAXIMUM_ALLOWED,
|
|
// inspect them until one of the following happens:
|
|
//
|
|
// 1. An ACE is found which explicitly denies one of the requested
|
|
// access rights. In this case checking stops immediately and
|
|
// access is (explicitly) denied.
|
|
//
|
|
// 2. All the requested accesses are explicitly granted by one or
|
|
// more ACEs. In this case checking stops immediately and
|
|
// access is (explicitly) allowed.
|
|
//
|
|
//
|
|
// 3. All the ACEs have been inspected inspected and there is at least
|
|
// one requested access right that has not been explicitly allowed.
|
|
// In this case, access is (implicitly) denied.
|
|
//
|
|
// If the desired access is MAXIMUM_ALLOWED, inspect all the ACEs.
|
|
//
|
|
|
|
PISID pSid;
|
|
BYTE* pByte;
|
|
|
|
CAccumulatedPermissions accumulatedPermissions( pObjectTypeList, ObjectTypeListLength);
|
|
|
|
if(!accumulatedPermissions.Initialized())
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopAccessCheckByType - CAccumulatedPermissions failed to initialize.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
*pdwGrantedAccessMask = 0;
|
|
*pbAccessStatus = FALSE;
|
|
|
|
|
|
//
|
|
// Log SID information contained in the RsopToken.
|
|
//
|
|
|
|
CRsopToken* pToken = static_cast<CRsopToken*>(pRsopToken);
|
|
for(CTLink<CSid>* pLink = pToken->m_pSidsHead; pLink; pLink = pLink->m_pNext)
|
|
{
|
|
LogSid(pLink->m_pData->GetSidPtr());
|
|
}
|
|
|
|
|
|
//
|
|
// The first ACE immediately follows the DACL structure. We don't know up front
|
|
// the type of ACE so we get the ACE header which has a format common to all
|
|
// ACE types.
|
|
//
|
|
|
|
PACE_HEADER pAceHeader = reinterpret_cast<PACE_HEADER>(pDacl+1);
|
|
|
|
for(DWORD i=0; i<dwAceCount; i++)
|
|
{
|
|
bool bAccessExplicitlyDenied;
|
|
HRESULT hr = ProcessAce(pAceHeader,
|
|
pRsopToken,
|
|
pObjectTypeList,
|
|
ObjectTypeListLength,
|
|
dwDesiredAccessMask,
|
|
accumulatedPermissions,
|
|
&bAccessExplicitlyDenied);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopAccessCheckByType - ProcessAce failed. Return code: 0x%08X", hr);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// If, this ACE explicitly denies any of the requested access rights,
|
|
// stop immediately. Access is denied.
|
|
// ProcessAce will never set this variable to true when dwDesiredAccessMask
|
|
// is MAXIMUM_ALLOWED.
|
|
//
|
|
|
|
if(bAccessExplicitlyDenied)
|
|
{
|
|
*pdwGrantedAccessMask = 0;
|
|
*pbAccessStatus = FALSE;
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - An ACE explicitly denies any of the requested access rights. Access is denied.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// If, after processing this ACE all requested access rights have been granted,
|
|
// stop immediately. Access is granted.
|
|
//
|
|
|
|
DWORD dwAccumulatedPermissions = accumulatedPermissions.GetAccumulatedPermissions();
|
|
if((dwDesiredAccessMask != MAXIMUM_ALLOWED) && (dwAccumulatedPermissions == dwDesiredAccessMask))
|
|
{
|
|
*pdwGrantedAccessMask = dwDesiredAccessMask;
|
|
*pbAccessStatus = TRUE;
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - dwDesiredAccessMask != MAXIMUM_ALLOWED && dwAccumulatedPermissions == dwDesiredAccessMask. Access is granted.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Otherwise, point to the next ACE.
|
|
//
|
|
|
|
pAceHeader = reinterpret_cast<PACE_HEADER>(reinterpret_cast<BYTE*>(pAceHeader) + pAceHeader->AceSize);
|
|
}
|
|
|
|
if(dwDesiredAccessMask == MAXIMUM_ALLOWED)
|
|
{
|
|
*pdwGrantedAccessMask = accumulatedPermissions.GetAccumulatedPermissions();
|
|
*pbAccessStatus = *pdwGrantedAccessMask ? TRUE : FALSE;
|
|
}
|
|
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopAccessCheckByType - Leaving.");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: RsopFileAccessCheck
|
|
//
|
|
// Description: Determines whether the security descriptor pointed to by pSecurityDescriptor
|
|
// grants the set of file access rights specified in dwDesiredAccessMask
|
|
// to the client identified by the RSOPTOKEN pointed to by pRsopToken.
|
|
//
|
|
// Parameters: - pszFileName: Pointer to an existing filename.
|
|
// - pRsopToken: Pointer to a valid RSOPTOKEN against which access
|
|
// is to be checked.
|
|
// - dwDesiredAccessMask: Mask of requested generic and/or standard and/or specific access rights,
|
|
// - pdwGrantedAccessMask: On success, if pbAccessStatus is true, it contains
|
|
// the mask of standard and specific rights granted.
|
|
// If pbAccessStatus is false, it is set to 0.
|
|
// On failure, it is not modified.
|
|
// - pbAccessStatus: On success, indicates wether the requested set
|
|
// of access rights was granted.
|
|
// On failure, it is not modified
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
// History: 7/30/99 leonardm Created.
|
|
//
|
|
//******************************************************************************
|
|
HRESULT RsopFileAccessCheck(LPTSTR pszFileName,
|
|
PRSOPTOKEN pRsopToken,
|
|
DWORD dwDesiredAccessMask,
|
|
LPDWORD pdwGrantedAccessMask,
|
|
LPBOOL pbAccessStatus)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Entering.");
|
|
|
|
|
|
//
|
|
// Check for invalid arguments.
|
|
//
|
|
|
|
if( !pszFileName |!pRsopToken | !pdwGrantedAccessMask | !pbAccessStatus)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopFileAccessCheck - Function called with invalid parameters.");
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Leaving.");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Attempt to get a handle with READ_CONTROL access right that can be used to
|
|
// read the security descriptor.
|
|
//
|
|
|
|
XHandle hFile = CreateFile( pszFileName,
|
|
READ_CONTROL,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopFileAccessCheck - Call to CreateFile failed. Filename: %s. Last error: 0x%08X", pszFileName, GetLastError());
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Leaving.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Use the handle to get the security descriptor with only the DACL in it.
|
|
//
|
|
|
|
PACL pDacl;
|
|
XPtrLF<SECURITY_DESCRIPTOR>xpSecurityDescriptor = NULL;
|
|
DWORD status = GetSecurityInfo( hFile,
|
|
SE_FILE_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
&pDacl,
|
|
NULL,
|
|
reinterpret_cast<void**>(&xpSecurityDescriptor));
|
|
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopFileAccessCheck - Call to GetSecurityInfo failed. Return: 0x%08X", status);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Leaving.");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// This will be used by RSOPAccessCheckByType to map generic rights specified in
|
|
// dwDesiredAccessMask to standard and specific rights.
|
|
//
|
|
|
|
GENERIC_MAPPING FileGenericMapping;
|
|
FileGenericMapping.GenericRead = FILE_GENERIC_READ;
|
|
FileGenericMapping.GenericWrite = FILE_GENERIC_WRITE;
|
|
FileGenericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
|
|
FileGenericMapping.GenericAll = FILE_ALL_ACCESS;
|
|
|
|
|
|
//
|
|
// Call RsopAccessCheckByType to do the actual checking.
|
|
//
|
|
|
|
HRESULT hr = RsopAccessCheckByType( xpSecurityDescriptor,
|
|
NULL,
|
|
pRsopToken,
|
|
dwDesiredAccessMask,
|
|
NULL,
|
|
0,
|
|
&FileGenericMapping,
|
|
NULL,
|
|
0,
|
|
pdwGrantedAccessMask,
|
|
pbAccessStatus);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Leaving successfully.");
|
|
}
|
|
else
|
|
{
|
|
dbg.Msg(DEBUG_MESSAGE_WARNING, L"RsopFileAccessCheck - Call to RsopAccessCheckByType failed. Return: 0x%08X", hr);
|
|
dbg.Msg(DEBUG_MESSAGE_VERBOSE, L"RsopFileAccessCheck - Leaving.");
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Function: RsopSidsFromToken
|
|
//
|
|
// Description: Returns all the sids in the token
|
|
//
|
|
// Parameters: pRsopToken -- an rsop token from which to obtain sids
|
|
// ppGroups -- a pointer to the address of a TOKEN_GROUPS structure
|
|
// that will be allocated by this function and will contain
|
|
// references to the sids. The caller should free this
|
|
// pointer with LocalFree -- this will also free all memory
|
|
// referenced by the structure.
|
|
//
|
|
// Return: S_OK on success. An HRESULT error code on failure.
|
|
//
|
|
//
|
|
//******************************************************************************
|
|
HRESULT RsopSidsFromToken(PRSOPTOKEN pRsopToken,
|
|
PTOKEN_GROUPS* ppGroups)
|
|
{
|
|
HRESULT hr;
|
|
CRsopToken* pToken;
|
|
|
|
//
|
|
// Initializations
|
|
//
|
|
hr = S_OK;
|
|
*ppGroups = NULL;
|
|
|
|
pToken = (CRsopToken*) pRsopToken;
|
|
|
|
//
|
|
// First, determine the number of groups and the size
|
|
// needed for each sid
|
|
//
|
|
CTLink<CSid>* pCurrent;
|
|
DWORD cbSize;
|
|
DWORD cGroups;
|
|
|
|
cbSize = 0;
|
|
cGroups = 0;
|
|
|
|
//
|
|
// Iterate through each sid, adding its size to the total
|
|
// needed to store the sids
|
|
//
|
|
for ( pCurrent = pToken->m_pSidsHead;
|
|
pCurrent;
|
|
pCurrent = pCurrent->m_pNext)
|
|
{
|
|
cbSize += RtlLengthSid(pCurrent->m_pData->GetSidPtr());
|
|
cGroups++;
|
|
}
|
|
|
|
//
|
|
// Add in the size of the fixed portion of the return structure.
|
|
// Note that the fixed portion of the structure already has
|
|
// space for one group, so we exclude that group from the amount
|
|
// neeeded to allocate if we are allocating at least one group
|
|
//
|
|
cbSize += sizeof(TOKEN_GROUPS) + (sizeof(SID_AND_ATTRIBUTES) *
|
|
(cGroups - (cGroups ? 1 : 0)));
|
|
|
|
//
|
|
// Now allocate space for the groups
|
|
//
|
|
*ppGroups = (PTOKEN_GROUPS) LocalAlloc( LPTR, cbSize );
|
|
|
|
if ( !*ppGroups )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Set the count member of the structure
|
|
//
|
|
(*ppGroups)->GroupCount = cGroups;
|
|
|
|
//
|
|
// If there are groups, copy the sids
|
|
//
|
|
if ( 0 != cGroups )
|
|
{
|
|
PSID pCurrentSid;
|
|
PSID_AND_ATTRIBUTES pCurrentGroup;
|
|
|
|
//
|
|
// Set the current sid to an offset past the
|
|
// array of SID_AND_ATTRIBUTE structures that
|
|
// represents each group
|
|
//
|
|
pCurrentSid = &((*ppGroups)->Groups[cGroups]);
|
|
|
|
//
|
|
// Set the current group to the first SID_AND_ATTRIBUTE structure
|
|
//
|
|
pCurrentGroup = (PSID_AND_ATTRIBUTES) &((*ppGroups)->Groups);
|
|
|
|
//
|
|
// We have no information in the rsop token regarding
|
|
// the attributes, so we clear this member
|
|
//
|
|
pCurrentGroup->Attributes = 0;
|
|
|
|
//
|
|
// Iterate through each group and copy it
|
|
//
|
|
for (pCurrent = pToken->m_pSidsHead;
|
|
pCurrent;
|
|
pCurrent = pCurrent->m_pNext)
|
|
{
|
|
DWORD cbSid;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Determine the length of the source sid
|
|
//
|
|
cbSid = RtlLengthSid(pCurrent->m_pData->GetSidPtr());
|
|
|
|
//
|
|
// Copy the source sid to the current sid
|
|
//
|
|
Status = RtlCopySid(
|
|
cbSid,
|
|
pCurrentSid,
|
|
pCurrent->m_pData->GetSidPtr());
|
|
|
|
//
|
|
// Check for errors
|
|
//
|
|
if (STATUS_SUCCESS != Status)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(Status);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the current group's sid reference to the
|
|
// current sid
|
|
//
|
|
pCurrentGroup->Sid = pCurrentSid;
|
|
|
|
//
|
|
// Move our current sid offset forward by the length of
|
|
// the current sid. Move our group reference forward as well.
|
|
//
|
|
pCurrentSid = (PSID) (((BYTE*) pCurrentSid) + cbSid);
|
|
pCurrentGroup++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free any memory on failure and remove
|
|
// any reference to it
|
|
//
|
|
if (FAILED(hr))
|
|
{
|
|
LocalFree(*ppGroups);
|
|
*ppGroups = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|