Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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