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.
1159 lines
25 KiB
1159 lines
25 KiB
// Copyright (c) 2000-2002 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// Created: 4/21/2000, Kevin Hughes
|
|
|
|
#include "precomp.h"
|
|
#include <vector>
|
|
#include <assertbreak.h>
|
|
#include "AccessEntry.h" // CAccessEntry class
|
|
#include "AccessEntryList.h"
|
|
#include "DACL.h" // CDACL class
|
|
#include "SACL.h"
|
|
|
|
#include "securitydescriptor.h"
|
|
#include "CToken.h"
|
|
|
|
#include <autoptr.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CToken base class
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
CToken::CToken()
|
|
: m_hToken(NULL),
|
|
m_fIsValid(false),
|
|
m_fClose(true),
|
|
m_dwLastError(ERROR_SUCCESS),
|
|
m_psdDefault(NULL)
|
|
{
|
|
::SetLastError(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
// Copy constructor
|
|
CToken::CToken(
|
|
const CToken &rTok)
|
|
|
|
: m_hToken(NULL),
|
|
m_fIsValid(false),
|
|
m_fClose(true),
|
|
m_dwLastError(ERROR_SUCCESS),
|
|
m_psdDefault(NULL)
|
|
{
|
|
Duplicate(rTok);
|
|
}
|
|
|
|
|
|
CToken::~CToken(void)
|
|
{
|
|
CleanToken () ;
|
|
}
|
|
|
|
void CToken::CleanToken ()
|
|
{
|
|
// Close token handle
|
|
if ( m_fClose )
|
|
{
|
|
if ( m_hToken && INVALID_HANDLE_VALUE != m_hToken )
|
|
{
|
|
::CloseHandle( m_hToken );
|
|
}
|
|
}
|
|
|
|
if(m_psdDefault)
|
|
{
|
|
delete m_psdDefault;
|
|
m_psdDefault = NULL;
|
|
}
|
|
|
|
// Initialize data
|
|
m_hToken = NULL;
|
|
m_fIsValid = false;
|
|
m_fClose = true;
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
// tokenType
|
|
|
|
BOOL CToken::GetTokenType ( TOKEN_TYPE& type ) const
|
|
{
|
|
BOOL bResult = FALSE ;
|
|
DWORD dwReturnLength = 0L ;
|
|
bResult = GetTokenInformation (
|
|
m_hToken ,
|
|
TokenType ,
|
|
&type ,
|
|
sizeof ( TOKEN_TYPE ) ,
|
|
&dwReturnLength
|
|
) ;
|
|
|
|
return bResult ;
|
|
}
|
|
|
|
// Duplicate CToken
|
|
BOOL CToken::Duplicate (
|
|
const CToken& tokDup,
|
|
BOOL bReInit,
|
|
DWORD dwDesiredAccess,
|
|
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
|
|
TOKEN_TYPE type
|
|
|
|
)
|
|
{
|
|
CleanToken () ;
|
|
|
|
// Duplicate token handle
|
|
HANDLE hTmp = NULL;
|
|
BOOL fResult = FALSE;
|
|
|
|
if ( bReInit )
|
|
{
|
|
fResult = ::DuplicateTokenEx (
|
|
tokDup.GetTokenHandle(),
|
|
dwDesiredAccess,
|
|
NULL,
|
|
ImpersonationLevel,
|
|
type,
|
|
&hTmp
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
SECURITY_INFORMATION siFlags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
|
|
// Determine the length needed for self-relative SD
|
|
DWORD dwLengthNeeded = 0;
|
|
|
|
fResult = ::GetKernelObjectSecurity (
|
|
tokDup.GetTokenHandle(),
|
|
siFlags,
|
|
NULL,
|
|
0,
|
|
&dwLengthNeeded
|
|
);
|
|
|
|
dwError = ::GetLastError();
|
|
|
|
if( !fResult )
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
wmilib::auto_buffer < BYTE > pDeleteSD ;
|
|
|
|
if ( ERROR_ACCESS_DENIED == dwError )
|
|
{
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
|
|
if ( ERROR_INSUFFICIENT_BUFFER == dwError )
|
|
{
|
|
pSD = new BYTE[dwLengthNeeded];
|
|
pDeleteSD.reset( reinterpret_cast < BYTE* > ( pSD ) ) ;
|
|
|
|
if(pSD)
|
|
{
|
|
// Now obtain security descriptor
|
|
if(::GetKernelObjectSecurity (
|
|
tokDup.GetTokenHandle(),
|
|
siFlags,
|
|
pSD,
|
|
dwLengthNeeded,
|
|
&dwLengthNeeded
|
|
)
|
|
)
|
|
{
|
|
dwError = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == dwError )
|
|
{
|
|
SECURITY_ATTRIBUTES t_SecurityAttributes ;
|
|
t_SecurityAttributes.nLength = ( pSD ) ? GetSecurityDescriptorLength ( pSD ) : 0 ;
|
|
t_SecurityAttributes.lpSecurityDescriptor = pSD ;
|
|
t_SecurityAttributes.bInheritHandle = FALSE ;
|
|
|
|
fResult = ::DuplicateTokenEx (
|
|
tokDup.GetTokenHandle() ,
|
|
dwDesiredAccess ,
|
|
( pSD ) ? &t_SecurityAttributes : NULL ,
|
|
ImpersonationLevel ,
|
|
type ,
|
|
&hTmp
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
m_hToken = hTmp;
|
|
|
|
if ( bReInit )
|
|
{
|
|
m_dwLastError = ReinitializeAll();
|
|
}
|
|
|
|
m_fIsValid = true;
|
|
}
|
|
|
|
return fResult ;
|
|
}
|
|
|
|
|
|
CToken& CToken::operator=(
|
|
const CToken& rTok)
|
|
{
|
|
Duplicate(rTok);
|
|
return *this;
|
|
}
|
|
|
|
|
|
DWORD CToken::ReinitializeAll()
|
|
{
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
|
|
dwRet = ReinitializeOwnerSid();
|
|
if(dwRet == ERROR_SUCCESS )
|
|
{
|
|
dwRet = ReinitializeDefaultSD();
|
|
}
|
|
|
|
if(dwRet == ERROR_SUCCESS )
|
|
{
|
|
dwRet = RebuildGroupList();
|
|
}
|
|
|
|
if(dwRet == ERROR_SUCCESS )
|
|
{
|
|
dwRet = RebuildPrivilegeList();
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
DWORD CToken::ReinitializeOwnerSid()
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
|
|
PTOKEN_USER ptokusr = NULL;
|
|
|
|
try
|
|
{
|
|
GTI(TokenUser, (void**)&ptokusr);
|
|
|
|
if(ptokusr)
|
|
{
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
m_sidTokenOwner = CSid(ptokusr->User.Sid);
|
|
}
|
|
|
|
delete ptokusr; ptokusr = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(ptokusr)
|
|
{
|
|
delete ptokusr; ptokusr = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
DWORD CToken::ReinitializeDefaultSD()
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
|
|
// Clean up default SD
|
|
if(m_psdDefault)
|
|
{
|
|
delete m_psdDefault;
|
|
m_psdDefault = NULL;
|
|
}
|
|
|
|
CSid* psidDefOwner = NULL;
|
|
CDACL* pdaclDefault = NULL;
|
|
PTOKEN_OWNER ptokowner = NULL;
|
|
PTOKEN_DEFAULT_DACL pdefdacl = NULL;
|
|
|
|
// Get default owner
|
|
try
|
|
{
|
|
GTI(TokenOwner, (void**)&ptokowner);
|
|
if(ptokowner)
|
|
{
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
psidDefOwner = new CSid(ptokowner->Owner);
|
|
}
|
|
}
|
|
|
|
GTI(TokenDefaultDacl, (void**)&pdefdacl);
|
|
if(pdefdacl)
|
|
{
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
pdaclDefault = new CDACL;
|
|
m_dwLastError = pdaclDefault->Init(
|
|
pdefdacl->DefaultDacl);
|
|
}
|
|
}
|
|
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
m_psdDefault = new CSecurityDescriptor(
|
|
psidDefOwner,
|
|
false,
|
|
NULL,
|
|
false,
|
|
pdaclDefault,
|
|
false,
|
|
false,
|
|
NULL,
|
|
false,
|
|
false);
|
|
}
|
|
|
|
if(psidDefOwner)
|
|
{
|
|
delete psidDefOwner; psidDefOwner = NULL;
|
|
}
|
|
if(pdaclDefault)
|
|
{
|
|
delete pdaclDefault; pdaclDefault = NULL;
|
|
}
|
|
if(ptokowner)
|
|
{
|
|
delete ptokowner; ptokowner = NULL;
|
|
}
|
|
if(pdefdacl)
|
|
{
|
|
delete pdefdacl; pdefdacl = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(psidDefOwner)
|
|
{
|
|
delete psidDefOwner; psidDefOwner = NULL;
|
|
}
|
|
if(pdaclDefault)
|
|
{
|
|
delete pdaclDefault; pdaclDefault = NULL;
|
|
}
|
|
if(ptokowner)
|
|
{
|
|
delete ptokowner; ptokowner = NULL;
|
|
}
|
|
if(pdefdacl)
|
|
{
|
|
delete pdefdacl; pdefdacl = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
|
|
DWORD CToken::RebuildGroupList( void )
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
// Release the old list
|
|
m_vecGroupsAndAttributes.clear();
|
|
|
|
// Obtain and initialize groups from token
|
|
PTOKEN_GROUPS ptg = NULL;
|
|
|
|
try
|
|
{
|
|
GTI(TokenGroups, (void**)&ptg);
|
|
|
|
if(ptg)
|
|
{
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
for(long m = 0;
|
|
m < ptg->GroupCount;
|
|
m++)
|
|
{
|
|
m_vecGroupsAndAttributes.push_back(
|
|
CSidAndAttribute(
|
|
CSid(ptg->Groups[m].Sid),
|
|
ptg->Groups[m].Attributes));
|
|
}
|
|
}
|
|
delete ptg; ptg = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(ptg)
|
|
{
|
|
delete ptg; ptg = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// If we are here, then groups are initialized
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
DWORD CToken::RebuildPrivilegeList()
|
|
{
|
|
// Release the old list
|
|
m_vecPrivileges.clear();
|
|
|
|
// Obtain and initialize groups from token
|
|
PTOKEN_PRIVILEGES ptp = NULL;
|
|
const int NAME_SIZE = 128;
|
|
BYTE bytePrivilegeName[NAME_SIZE];
|
|
DWORD dwNameSize;
|
|
|
|
try
|
|
{
|
|
GTI(TokenPrivileges, (void**)&ptp);
|
|
|
|
if(ptp)
|
|
{
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
for(long m = 0;
|
|
m < ptp->PrivilegeCount &&
|
|
m_dwLastError == ERROR_SUCCESS;
|
|
m++)
|
|
{
|
|
dwNameSize = NAME_SIZE;
|
|
if(::LookupPrivilegeName(
|
|
NULL,
|
|
&(ptp->Privileges[m].Luid),
|
|
(WCHAR*) bytePrivilegeName,
|
|
&dwNameSize))
|
|
{
|
|
m_vecPrivileges.push_back(Privilege(
|
|
CHString((LPWSTR) bytePrivilegeName),
|
|
ptp->Privileges[m].Attributes));
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
}
|
|
}
|
|
delete ptp; ptp = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(ptp)
|
|
{
|
|
delete ptp; ptp = NULL;
|
|
}
|
|
}
|
|
|
|
// If we are here, then privileges are initialized
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
DWORD CToken::GTI(
|
|
TOKEN_INFORMATION_CLASS TokenInformationClass,
|
|
PVOID* ppvBuff)
|
|
{
|
|
::SetLastError(ERROR_SUCCESS);
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
DWORD dwRetSize = 0;
|
|
|
|
if(!::GetTokenInformation(
|
|
m_hToken,
|
|
TokenInformationClass,
|
|
NULL,
|
|
0L,
|
|
&dwRetSize))
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
|
|
if(m_dwLastError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// now get it for real...
|
|
::SetLastError(ERROR_SUCCESS);
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
*ppvBuff = (PVOID) new BYTE[dwRetSize];
|
|
DWORD dwTmp = dwRetSize;
|
|
if(*ppvBuff)
|
|
{
|
|
if(!::GetTokenInformation(
|
|
m_hToken,
|
|
TokenInformationClass,
|
|
*ppvBuff,
|
|
dwTmp,
|
|
&dwRetSize))
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
|
|
bool CToken::GetPrivilege(
|
|
Privilege* privOut,
|
|
long lPos) const
|
|
{
|
|
bool fRet = false;
|
|
if(privOut)
|
|
{
|
|
if(lPos >= 0 &&
|
|
lPos < m_vecPrivileges.size())
|
|
{
|
|
*privOut = m_vecPrivileges[lPos];
|
|
fRet = true;
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
bool CToken::GetGroup(
|
|
CSid* sidOut,
|
|
long lPos) const
|
|
{
|
|
bool fRet = false;
|
|
if(sidOut)
|
|
{
|
|
if(lPos >= 0 &&
|
|
lPos < m_vecGroupsAndAttributes.size())
|
|
{
|
|
*sidOut = m_vecGroupsAndAttributes[lPos].m_sid;
|
|
fRet = true;
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
long CToken::GetPrivCount() const
|
|
{
|
|
return m_vecPrivileges.size();
|
|
}
|
|
|
|
|
|
long CToken::GetGroupCount() const
|
|
{
|
|
|
|
return m_vecGroupsAndAttributes.size();
|
|
}
|
|
|
|
|
|
|
|
HANDLE CToken::GetTokenHandle() const
|
|
{
|
|
return m_hToken;
|
|
}
|
|
|
|
|
|
bool CToken::GetTokenOwner(
|
|
CSid* sidOwner) const
|
|
{
|
|
bool fRet = false;
|
|
if(sidOwner)
|
|
{
|
|
sidOwner = new CSid(m_sidTokenOwner);
|
|
fRet = true;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// NOTE: hands back internal descriptor.
|
|
bool CToken::GetDefaultSD(
|
|
CSecurityDescriptor** ppsdDefault)
|
|
{
|
|
bool fRet = false;
|
|
|
|
if(ppsdDefault)
|
|
{
|
|
if(m_psdDefault)
|
|
{
|
|
*ppsdDefault = m_psdDefault;
|
|
fRet = true;
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
DWORD CToken::SetDefaultSD(
|
|
CSecurityDescriptor& SourceSD)
|
|
{
|
|
::SetLastError(ERROR_SUCCESS);
|
|
|
|
// Inject new default info into token
|
|
|
|
// Set new default owner
|
|
CSid SidOwner;
|
|
CDACL cd;
|
|
SourceSD.GetOwner(SidOwner);
|
|
|
|
TOKEN_OWNER to;
|
|
to.Owner = SidOwner.GetPSid();
|
|
BOOL fResult = ::SetTokenInformation(
|
|
m_hToken,
|
|
TokenOwner,
|
|
&to,
|
|
sizeof(TOKEN_OWNER));
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
// Set new default DACL
|
|
TOKEN_DEFAULT_DACL tdd;
|
|
|
|
if(SourceSD.GetDACL(cd))
|
|
{
|
|
CAccessEntryList cael;
|
|
if(cd.GetMergedACL(cael))
|
|
{
|
|
PACL paclOut = NULL;
|
|
if((m_dwLastError =
|
|
cael.FillWin32ACL(paclOut)) ==
|
|
ERROR_SUCCESS)
|
|
{
|
|
tdd.DefaultDacl = paclOut;
|
|
fResult = ::SetTokenInformation(
|
|
m_hToken,
|
|
TokenDefaultDacl,
|
|
&tdd,
|
|
sizeof(TOKEN_DEFAULT_DACL));
|
|
|
|
if(fResult)
|
|
{
|
|
// Reference new CSD in member variable
|
|
if(m_psdDefault)
|
|
{
|
|
delete m_psdDefault; m_psdDefault = NULL;
|
|
}
|
|
|
|
m_psdDefault = new CSecurityDescriptor(
|
|
&SidOwner,
|
|
false,
|
|
NULL,
|
|
false,
|
|
&cd,
|
|
false,
|
|
false,
|
|
NULL,
|
|
false,
|
|
false);
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
DWORD CToken::EnablePrivilege(
|
|
CHString& strPrivilegeName )
|
|
{
|
|
// Check whether privilege exists
|
|
bool fPrivilegeListed = false;
|
|
|
|
for(long m = 0;
|
|
m < m_vecPrivileges.size();
|
|
m++)
|
|
{
|
|
if(m_vecPrivileges[m].chstrName.CompareNoCase(strPrivilegeName) == 0)
|
|
{
|
|
fPrivilegeListed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!fPrivilegeListed )
|
|
{
|
|
m_dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
LUID luid;
|
|
BOOL fResult = ::LookupPrivilegeValue(
|
|
NULL, // use local computer
|
|
strPrivilegeName,
|
|
&luid);
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
TOKEN_PRIVILEGES tpNewState;
|
|
tpNewState.PrivilegeCount = 1;
|
|
tpNewState.Privileges[0].Luid = luid;
|
|
tpNewState.Privileges[0].Attributes =
|
|
SE_PRIVILEGE_ENABLED;
|
|
|
|
TOKEN_PRIVILEGES tpPreviousState;
|
|
DWORD dwSizePreviousState =
|
|
sizeof(TOKEN_PRIVILEGES);
|
|
|
|
fResult = ::AdjustTokenPrivileges(
|
|
m_hToken,
|
|
FALSE,
|
|
&tpNewState,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
&tpPreviousState,
|
|
&dwSizePreviousState);
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = RebuildPrivilegeList();
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
DWORD CToken::DisablePrivilege(
|
|
CHString& chstrPrivilegeName)
|
|
{
|
|
// Check whether privilege exists
|
|
bool fPrivilegeListed = false;
|
|
|
|
for(long m = 0;
|
|
m < m_vecPrivileges.size();
|
|
m++)
|
|
{
|
|
if(m_vecPrivileges[m].chstrName.CompareNoCase(chstrPrivilegeName) == 0)
|
|
{
|
|
fPrivilegeListed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!fPrivilegeListed )
|
|
{
|
|
m_dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
LUID luid;
|
|
BOOL fResult = ::LookupPrivilegeValue(
|
|
NULL, // use local computer
|
|
chstrPrivilegeName,
|
|
&luid);
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
TOKEN_PRIVILEGES tpNewState;
|
|
tpNewState.PrivilegeCount = 1;
|
|
tpNewState.Privileges[0].Luid = luid;
|
|
tpNewState.Privileges[0].Attributes =
|
|
0;
|
|
|
|
TOKEN_PRIVILEGES tpPreviousState;
|
|
DWORD dwSizePreviousState =
|
|
sizeof(TOKEN_PRIVILEGES);
|
|
|
|
fResult = ::AdjustTokenPrivileges(
|
|
m_hToken,
|
|
FALSE,
|
|
&tpNewState,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
&tpPreviousState,
|
|
&dwSizePreviousState);
|
|
|
|
if(!fResult)
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
m_dwLastError = RebuildPrivilegeList();
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_dwLastError;
|
|
}
|
|
|
|
|
|
void CToken::Dump(WCHAR* pszFileName)
|
|
{
|
|
/*
|
|
* Algorithm:
|
|
* 1. Dump token owner SID, name, and domain.
|
|
* 2. Dump all group SIDs with names and domains.
|
|
* 3. Dump list of privileges with attributes.
|
|
* 4. Dump default owner.
|
|
* 5. Dump default DACL.
|
|
*/
|
|
|
|
CHString strFileName = pszFileName;
|
|
|
|
// If file name is not empty - create the file
|
|
FILE* fp = NULL;
|
|
if(!strFileName.IsEmpty())
|
|
{
|
|
fp = _wfopen((LPCWSTR)strFileName, L"a");
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!fp) return;
|
|
|
|
|
|
// Write to the file
|
|
DWORD dwBytesWritten = 0;
|
|
CHString strCRLF = L"\r\n";
|
|
CHString strDump;
|
|
|
|
{
|
|
strDump = L"Token owner: " + m_sidTokenOwner.GetAccountName() + strCRLF;
|
|
fputws(strDump, fp);
|
|
|
|
strDump = L"Domain: " + m_sidTokenOwner.GetDomainName() + strCRLF;
|
|
fputws(strDump, fp);
|
|
|
|
strDump = L"SID: " + m_sidTokenOwner.GetSidString() + strCRLF + strCRLF;
|
|
fputws(strDump, fp);
|
|
}
|
|
|
|
// Dump all groups
|
|
fputws(strCRLF, fp);
|
|
fputws(strCRLF, fp);
|
|
|
|
for(long m = 0;
|
|
m < m_vecGroupsAndAttributes.size();
|
|
m++)
|
|
{
|
|
// Write to the file as well
|
|
{
|
|
strDump = L"Member of this group: " + m_vecGroupsAndAttributes[m].m_sid.GetSidString() + strCRLF;
|
|
fputws(strDump, fp);
|
|
|
|
strDump = L"\t(" + m_vecGroupsAndAttributes[m].m_sid.GetAccountName() + L" in " +
|
|
m_vecGroupsAndAttributes[m].m_sid.GetDomainName() + L" domain)" + strCRLF;
|
|
fputws(strDump, fp);
|
|
}
|
|
}
|
|
|
|
// Dump all privileges
|
|
fputws(strCRLF, fp);
|
|
fputws(strCRLF, fp);
|
|
|
|
for(m = 0;
|
|
m < m_vecPrivileges.size();
|
|
m++)
|
|
{
|
|
// Write to the file as well
|
|
{
|
|
|
|
strDump.Format( L"%d", m_vecPrivileges[m].dwAttributes );
|
|
strDump = L"Holds a " + m_vecPrivileges[m].chstrName + L" with attributes: " + strDump + strCRLF;
|
|
fputws(strDump, fp);
|
|
}
|
|
}
|
|
|
|
// Dump default information
|
|
fputws(strCRLF, fp);
|
|
fputws(strCRLF, fp);
|
|
{
|
|
strDump = strCRLF + L"Default information:" + strCRLF;
|
|
fputws(strDump, fp);
|
|
|
|
}
|
|
fputws(strCRLF, fp);
|
|
fputws(strCRLF, fp);
|
|
|
|
fclose(fp);
|
|
|
|
if(m_psdDefault)
|
|
{
|
|
m_psdDefault->DumpDescriptor(pszFileName);
|
|
}
|
|
}
|
|
|
|
|
|
// Deletes a member from the access token's
|
|
// member list, and applies the change.
|
|
bool CToken::DeleteGroup(
|
|
CSid& sidToDelete)
|
|
{
|
|
bool fRet = false;
|
|
|
|
// See if the group is in the membership
|
|
// vector...
|
|
bool fFoundIt = false;
|
|
|
|
SANDATTRIBUTE_VECTOR::iterator iter;
|
|
for(iter = m_vecGroupsAndAttributes.begin();
|
|
iter != m_vecGroupsAndAttributes.end();
|
|
iter++)
|
|
{
|
|
if(iter->m_sid.GetSidString().CompareNoCase(
|
|
sidToDelete.GetSidString()) == 0)
|
|
{
|
|
fFoundIt = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(fFoundIt)
|
|
{
|
|
m_vecGroupsAndAttributes.erase(iter);
|
|
|
|
// Now need to apply the changes. To do
|
|
// so, we need to construct a TOKEN_GROUPS
|
|
// structure...
|
|
fRet = ApplyTokenGroups();
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
// Adds a member to the specified group to
|
|
// the list of token groups.
|
|
bool CToken::AddGroup(
|
|
CSid& sidToAdd,
|
|
DWORD dwAttributes)
|
|
{
|
|
bool fRet = false;
|
|
|
|
// See if the group is in the membership
|
|
// vector...
|
|
bool fFoundIt = false;
|
|
|
|
SANDATTRIBUTE_VECTOR::iterator iter;
|
|
for(iter = m_vecGroupsAndAttributes.begin();
|
|
iter != m_vecGroupsAndAttributes.end();
|
|
iter++)
|
|
{
|
|
if(iter->m_sid.GetSidString().CompareNoCase(
|
|
sidToAdd.GetSidString()) == 0)
|
|
{
|
|
fFoundIt = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!fFoundIt)
|
|
{
|
|
m_vecGroupsAndAttributes.push_back(
|
|
CSidAndAttribute(
|
|
sidToAdd,
|
|
dwAttributes));
|
|
|
|
// Now need to apply the changes. To do
|
|
// so, we need to construct a TOKEN_GROUPS
|
|
// structure...
|
|
fRet = ApplyTokenGroups();
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
bool CToken::ApplyTokenGroups()
|
|
{
|
|
bool fRet = false;
|
|
PTOKEN_GROUPS ptg = NULL;
|
|
try
|
|
{
|
|
ptg = (PTOKEN_GROUPS) new BYTE[sizeof(DWORD) +
|
|
m_vecGroupsAndAttributes.size() * sizeof(SID_AND_ATTRIBUTES)];
|
|
|
|
if(ptg)
|
|
{
|
|
ptg->GroupCount = m_vecGroupsAndAttributes.size();
|
|
|
|
for(long m = 0;
|
|
m < m_vecGroupsAndAttributes.size();
|
|
m++)
|
|
{
|
|
ptg->Groups[m].Sid =
|
|
m_vecGroupsAndAttributes[m].m_sid.GetPSid();
|
|
ptg->Groups[m].Attributes =
|
|
m_vecGroupsAndAttributes[m].m_dwAttributes;
|
|
}
|
|
|
|
// Now we can alter the groups...
|
|
fRet = ::AdjustTokenGroups(
|
|
m_hToken,
|
|
FALSE,
|
|
ptg,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
delete ((PBYTE) ptg);
|
|
ptg = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(ptg)
|
|
{
|
|
delete ((PBYTE) ptg);
|
|
ptg = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CProcessToken class
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
CProcessToken::CProcessToken (
|
|
HANDLE hProcess,
|
|
bool fGetHandleOnly,
|
|
DWORD dwDesiredAccess
|
|
)
|
|
{
|
|
// Open handle to process access token
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
|
|
// If they didn't give us a process handle,
|
|
// use the current process.
|
|
if ( NULL == hProcess || INVALID_HANDLE_VALUE == hProcess )
|
|
{
|
|
if(!::OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
dwDesiredAccess,
|
|
&m_hToken ))
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hToken = hProcess;
|
|
m_fClose = false ;
|
|
}
|
|
|
|
if(!fGetHandleOnly)
|
|
{
|
|
m_dwLastError = ReinitializeAll();
|
|
}
|
|
|
|
if(m_dwLastError == ERROR_SUCCESS )
|
|
{
|
|
m_fIsValid = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CThreadToken class
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
CThreadToken::CThreadToken (
|
|
HANDLE hThread,
|
|
bool fGetHandleOnly,
|
|
bool fAccessCheckProcess,
|
|
DWORD dwDesiredAccess
|
|
)
|
|
{
|
|
m_dwLastError = ERROR_SUCCESS;
|
|
|
|
// If they didn't give us a thread handle,
|
|
// use the current thread.
|
|
if ( NULL == hThread || hThread == INVALID_HANDLE_VALUE )
|
|
{
|
|
// Open thread access token
|
|
HANDLE hToken = NULL;
|
|
|
|
if(!::OpenThreadToken(
|
|
GetCurrentThread(),
|
|
dwDesiredAccess,
|
|
fAccessCheckProcess,
|
|
&hToken))
|
|
{
|
|
m_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
{
|
|
m_hToken = hToken ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hToken = hThread ;
|
|
m_fClose = false ;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == m_dwLastError )
|
|
{
|
|
if ( !fGetHandleOnly )
|
|
{
|
|
m_dwLastError = ReinitializeAll();
|
|
}
|
|
}
|
|
|
|
if(m_dwLastError == ERROR_SUCCESS)
|
|
{
|
|
// If we are here, everything is initialized
|
|
m_fIsValid = TRUE;
|
|
}
|
|
}
|