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.
459 lines
13 KiB
459 lines
13 KiB
/*****************************************************************************/
|
|
|
|
|
|
|
|
/* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved /
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
//=================================================================
|
|
|
|
//
|
|
|
|
// AccessRights.CPP -- Base class for obtaining effective access
|
|
|
|
// rights.
|
|
|
|
//
|
|
|
|
// Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// Revisions: 6/11/99 a-kevhu Created
|
|
//
|
|
//=================================================================
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
#ifdef NTONLY
|
|
|
|
|
|
#include <assertbreak.h>
|
|
#include "AdvApi32Api.h"
|
|
#include "accctrl.h"
|
|
#include "sid.h"
|
|
#include "AccessEntryList.h"
|
|
#include "AccessRights.h"
|
|
|
|
//==============================================================================
|
|
// CONSTRUCTORS AND DESTRUCTORS
|
|
//==============================================================================
|
|
// Default initialization...
|
|
CAccessRights::CAccessRights(bool fUseCurThrTok /* = false */)
|
|
: m_dwError(ERROR_SUCCESS)
|
|
{
|
|
if(fUseCurThrTok)
|
|
{
|
|
// Initialize using the current thread token...
|
|
InitTrustee(true);
|
|
}
|
|
}
|
|
|
|
// Initialization specifying user only. Sid domain/account
|
|
// not resolved. ACL uninitialized.
|
|
CAccessRights::CAccessRights(const USER user, USER_SPECIFIER usp)
|
|
: m_dwError(ERROR_SUCCESS)
|
|
{
|
|
if(usp == USER_IS_PSID)
|
|
{
|
|
m_csid = CSid((PSID)user, NULL, false);
|
|
InitTrustee(false);
|
|
}
|
|
else if(usp == USER_IS_HANDLE)
|
|
{
|
|
ASSERT_BREAK(user != NULL);
|
|
InitTrustee(false, (HANDLE)user);
|
|
}
|
|
}
|
|
|
|
// Initialization of user and acl. Sid domain/account
|
|
// not resolved. ACL initialized.
|
|
CAccessRights::CAccessRights(const USER user, const PACL pacl, USER_SPECIFIER usp)
|
|
: m_ael(pacl, false),
|
|
m_dwError(ERROR_SUCCESS)
|
|
{
|
|
if(usp == USER_IS_PSID)
|
|
{
|
|
m_csid = CSid((PSID)user, NULL, false);
|
|
InitTrustee(false);
|
|
}
|
|
else if(usp == USER_IS_HANDLE)
|
|
{
|
|
ASSERT_BREAK(user != NULL);
|
|
InitTrustee(false, (HANDLE)user);
|
|
}
|
|
}
|
|
|
|
|
|
// Initialization of acl only. ACL Sids not resolved.
|
|
CAccessRights::CAccessRights(const PACL pacl, bool fUseCurThrTok /* = false */)
|
|
: m_ael(pacl, false),
|
|
m_dwError(ERROR_SUCCESS)
|
|
{
|
|
if(fUseCurThrTok)
|
|
{
|
|
// Initialize using the current thread token...
|
|
InitTrustee(true);
|
|
}
|
|
}
|
|
|
|
// Copy constructor
|
|
/* Not complete yet
|
|
CAccessRights::CAccessRights(const CAccessRights &RAccessRights)
|
|
{
|
|
// Copy members. We may or may not have either.
|
|
if(RAccessRights.m_csid.IsValid() && RAccessRights.m_csid.IsOK())
|
|
{
|
|
m_csid = RAccessRights.m_csid;
|
|
}
|
|
m_ael.Clear();
|
|
if(!RAccessRights.m_ael.IsEmpty())
|
|
{
|
|
// The best way to do this, to guarentee that the sids are not
|
|
// resolved into domain/name, is to gat a PACL, then reinitialize
|
|
// ourselves from it.
|
|
PACL paclNew = NULL;
|
|
try
|
|
{
|
|
if(RAccessRights.FillEmptyPACL(paclNew))
|
|
{
|
|
if(paclNew != NULL)
|
|
{
|
|
if(!m_ael.InitFromWin32ACL(paclNew, ALL_ACE_TYPES, false))
|
|
{
|
|
// If something went wrong, clean
|
|
// up after ourselves.
|
|
m_ael.Clear();
|
|
}
|
|
delete paclNew;
|
|
paclNew = NULL;
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(paclNew != NULL)
|
|
{
|
|
delete paclNew;
|
|
paclNew = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Destructor - members destruct themselves.
|
|
CAccessRights::~CAccessRights()
|
|
{
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// UTILITY FUNCTIONS
|
|
//==============================================================================
|
|
|
|
AR_RET_CODE CAccessRights::GetEffectiveAccessRights(PACCESS_MASK pAccessMask)
|
|
{
|
|
DWORD dwRet = AR_GENERIC_FAILURE;
|
|
CAdvApi32Api *pAdvApi32 = NULL;
|
|
PACL pacl = NULL;
|
|
try
|
|
{
|
|
pAdvApi32 = (CAdvApi32Api*) CResourceManager::sm_TheResourceManager.GetResource(g_guidAdvApi32Api, NULL);
|
|
if(pAdvApi32 != NULL)
|
|
{
|
|
if((dwRet = FillEmptyPACL(&pacl)) == ERROR_SUCCESS)
|
|
{
|
|
ASSERT_BREAK(pacl != NULL);
|
|
|
|
if(pacl != NULL)
|
|
{
|
|
if(m_csid.IsValid() && m_csid.IsOK())
|
|
{
|
|
pAdvApi32->GetEffectiveRightsFromAclW(pacl,
|
|
&m_trustee,
|
|
pAccessMask,
|
|
&dwRet);
|
|
}
|
|
else
|
|
{
|
|
dwRet = AR_BAD_SID;
|
|
}
|
|
delete pacl;
|
|
pacl = NULL;
|
|
}
|
|
}
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, pAdvApi32);
|
|
pAdvApi32 = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(pacl != NULL)
|
|
{
|
|
delete pacl;
|
|
pacl = NULL;
|
|
}
|
|
if(pAdvApi32 != NULL)
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, pAdvApi32);
|
|
pAdvApi32 = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
bool CAccessRights::InitTrustee(bool fInitFromCurrentThread, const HANDLE hToken)
|
|
{
|
|
bool fRet = false;
|
|
|
|
// The main thing done here is a sid is obtained and the TRUSTEE struct
|
|
// filled in.
|
|
|
|
if(fInitFromCurrentThread)
|
|
{
|
|
// Get the sid of the user/group of the current thread...
|
|
SmartCloseHandle hThreadToken;
|
|
if(::OpenThreadToken(::GetCurrentThread(), TOKEN_READ, FALSE, &hThreadToken))
|
|
{
|
|
InitSidFromToken(hThreadToken);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we were given a hToken, use it instead...
|
|
if(hToken != NULL)
|
|
{
|
|
InitSidFromToken(hToken);
|
|
}
|
|
}
|
|
|
|
// We should now have a valid sid in our member CSid (either from the
|
|
// InitSidFromToken calls or from construction).
|
|
// Now we need to initialize the TRUSTEE object. Check again that our sid
|
|
// is in good standing...
|
|
if(m_csid.IsValid() && m_csid.IsOK())
|
|
{
|
|
m_trustee.pMultipleTrustee = NULL;
|
|
m_trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
|
m_trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
m_trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; // we could be operating
|
|
// on behalf of a user,
|
|
// group, well-known-group,
|
|
// who knows.
|
|
|
|
m_trustee.ptstrName = (LPWSTR)m_csid.GetPSid();
|
|
fRet = true;
|
|
}
|
|
else
|
|
{
|
|
m_dwError = AR_BAD_SID;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
bool CAccessRights::InitSidFromToken(const HANDLE hThreadToken)
|
|
{
|
|
bool fRet = false;
|
|
|
|
if(hThreadToken != NULL)
|
|
{
|
|
DWORD dwLength = 0L;
|
|
DWORD dwReqLength = 0L;
|
|
PSID psid = NULL;
|
|
LPVOID pBuff = NULL;
|
|
if(!::GetTokenInformation(hThreadToken, TokenUser, NULL, 0, &dwReqLength))
|
|
{
|
|
if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// Allocate a buffer to hold the token info...
|
|
try
|
|
{
|
|
pBuff = new BYTE[dwReqLength];
|
|
if(pBuff != NULL)
|
|
{
|
|
dwLength = dwReqLength;
|
|
// Now that we have the right size buffer, call again...
|
|
if(::GetTokenInformation(hThreadToken,
|
|
TokenUser,
|
|
pBuff,
|
|
dwLength,
|
|
&dwReqLength))
|
|
{
|
|
if(pBuff != NULL)
|
|
{
|
|
TOKEN_USER *pTokUsr = (TOKEN_USER*)pBuff;
|
|
psid = pTokUsr->User.Sid;
|
|
|
|
ASSERT_BREAK((psid != NULL) && ::IsValidSid(psid));
|
|
|
|
if((psid != NULL) && ::IsValidSid(psid))
|
|
{
|
|
m_csid = CSid(psid, NULL, false);
|
|
fRet = true;
|
|
}
|
|
else
|
|
{
|
|
m_dwError = AR_BAD_SID;
|
|
}
|
|
}
|
|
}
|
|
delete pBuff;
|
|
pBuff = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(pBuff != NULL)
|
|
{
|
|
delete pBuff;
|
|
pBuff = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// Resets the user to the user to whom the current thread token belongs.
|
|
bool CAccessRights::SetUserToThisThread()
|
|
{
|
|
return InitTrustee(true, NULL);
|
|
}
|
|
|
|
// Resets the user to the user specified by psid or handle
|
|
bool CAccessRights::SetUser(const USER user, USER_SPECIFIER usp)
|
|
{
|
|
bool fRet = false;
|
|
if(usp == USER_IS_PSID)
|
|
{
|
|
CSid csidTemp((PSID)user);
|
|
if(csidTemp.IsValid() && csidTemp.IsOK())
|
|
{
|
|
m_csid = csidTemp;
|
|
fRet = true;
|
|
}
|
|
}
|
|
else if(usp == USER_IS_HANDLE)
|
|
{
|
|
fRet = InitSidFromToken((HANDLE)user);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// Resets the acl to the passed in PACL
|
|
bool CAccessRights::SetAcl(const PACL pacl)
|
|
{
|
|
bool fRet = false;
|
|
if(pacl != NULL)
|
|
{
|
|
m_ael.Clear();
|
|
if(m_ael.InitFromWin32ACL(pacl, ALL_ACE_TYPES, false) == ERROR_SUCCESS)
|
|
{
|
|
fRet = true;
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
// Gets us a filled out PACL, which must be freed by the caller, using delete.
|
|
AR_RET_CODE CAccessRights::FillEmptyPACL(PACL *paclOut)
|
|
{
|
|
DWORD dwRet = AR_GENERIC_FAILURE;
|
|
if(paclOut != NULL)
|
|
{
|
|
// The best way to do this, to guarentee that the sids are not
|
|
// resolved into domain/name, is to get a PACL, then reinitialize
|
|
// ourselves from it.
|
|
DWORD dwAclSize = 0L;
|
|
if(m_ael.NumEntries() > 0)
|
|
{
|
|
if(m_ael.CalculateWin32ACLSize(&dwAclSize))
|
|
{
|
|
if(dwAclSize > sizeof(ACL))
|
|
{
|
|
PACL paclTemp = NULL;
|
|
try
|
|
{
|
|
paclTemp = (PACL) new BYTE[dwAclSize];
|
|
if(paclTemp != NULL)
|
|
{
|
|
::InitializeAcl(paclTemp, dwAclSize, ACL_REVISION);
|
|
if((dwRet = m_ael.FillWin32ACL(paclTemp)) == ERROR_SUCCESS)
|
|
{
|
|
*paclOut = paclTemp;
|
|
dwRet = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(paclTemp != NULL)
|
|
{
|
|
delete paclTemp;
|
|
paclTemp = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = AR_ACL_EMPTY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = AR_BAD_ACL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = AR_ACL_EMPTY;
|
|
}
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
bool CAccessRights::GetCSid(CSid &csid, bool fResolve)
|
|
{
|
|
bool fRet = false;
|
|
if(m_dwError == ERROR_SUCCESS)
|
|
{
|
|
if(m_csid.IsValid() && m_csid.IsOK())
|
|
{
|
|
if(fResolve)
|
|
{
|
|
// Need to create a new one since ours doesn't
|
|
// have account or domain name resolved.
|
|
CSid csidTemp(m_csid.GetPSid());
|
|
if(csidTemp.IsValid() && csidTemp.IsOK())
|
|
{
|
|
csid = csidTemp;
|
|
fRet = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
csid = m_csid;
|
|
fRet = true;
|
|
}
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
#endif
|