Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4681 lines
112 KiB

// This is a part of the Active Template Library.
// Copyright (C) 1996-2001 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.
#ifndef __ATLSECURITY_H__
#define __ATLSECURITY_H__
#pragma once
#include <sddl.h>
#include <userenv.h>
#include <aclapi.h>
#include <atlcoll.h>
#include <atlstr.h>
namespace ATL
{
#pragma comment(lib, "userenv.lib")
class CSid
{
public:
CSid();
explicit CSid(LPCTSTR pszAccountName, LPCTSTR pszSystem = NULL);
explicit CSid(const SID *pSid, LPCTSTR pszSystem = NULL);
CSid(const SID_IDENTIFIER_AUTHORITY &IdentifierAuthority, BYTE nSubAuthorityCount, ...);
virtual ~CSid(){free(m_pSid);}
CSid(const CSid &rhs);
CSid &operator=(const CSid &rhs);
CSid(const SID &rhs);
CSid &operator=(const SID &rhs);
typedef CSimpleArray<CSid> CSidArray;
bool LoadAccount(LPCTSTR pszAccountName, LPCTSTR pszSystem = NULL);
bool LoadAccount(const SID *pSid, LPCTSTR pszSystem = NULL);
LPCTSTR AccountName() const;
LPCTSTR Domain() const;
LPCTSTR Sid() const;
const SID *GetPSID() const {return m_pSid;}
operator const SID *() const {return GetPSID();}
SID_NAME_USE SidNameUse() const {return m_SidNameUse;}
UINT GetLength() const
{ATLASSERT(IsValid()); return ::GetLengthSid(m_pSid);}
// SID functions
bool operator==(const CSid &rhs) const
{return 0 != ::EqualSid(m_pSid, rhs.m_pSid);}
bool operator==(const SID &rhs) const
{return 0 != ::EqualSid(m_pSid, const_cast<SID *>(&rhs));}
bool EqualPrefix(const CSid &rhs) const
{return 0 != ::EqualPrefixSid(m_pSid, rhs.m_pSid);}
bool EqualPrefix(const SID &rhs) const
{return 0 != ::EqualPrefixSid(m_pSid, const_cast<SID *>(&rhs));}
const SID_IDENTIFIER_AUTHORITY *GetPSID_IDENTIFIER_AUTHORITY() const
{ATLASSERT(IsValid()); return ::GetSidIdentifierAuthority(m_pSid);}
DWORD GetSubAuthority(DWORD nSubAuthority) const
{ATLASSERT(IsValid()); return *::GetSidSubAuthority(m_pSid, nSubAuthority);}
UCHAR GetSubAuthorityCount() const
{ATLASSERT(IsValid()); return *::GetSidSubAuthorityCount(m_pSid);}
bool IsValid() const {return 0 != ::IsValidSid(m_pSid);}
private:
void Copy(const SID &rhs);
void Clear();
void GetAccountNameAndDomain() const;
SID *m_pSid;
mutable SID_NAME_USE m_SidNameUse;
mutable CString m_strAccountName;
mutable CString m_strDomain;
mutable CString m_strSid;
CString m_strSystem;
};
// Well-known sids
namespace Sids
{
__declspec(selectany) extern const SID_IDENTIFIER_AUTHORITY
SecurityNullSidAuthority = SECURITY_NULL_SID_AUTHORITY,
SecurityWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY,
SecurityLocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY,
SecurityCreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY,
SecurityNonUniqueAuthority = SECURITY_NON_UNIQUE_AUTHORITY,
SecurityNTAuthority = SECURITY_NT_AUTHORITY;
// Universal
inline const CSid &Null()
{
static const CSid sid(SecurityNullSidAuthority, 1, SECURITY_NULL_RID);
return sid;
}
inline const CSid &World()
{
static const CSid sid(SecurityWorldSidAuthority, 1, SECURITY_WORLD_RID);
return sid;
}
inline const CSid &Local()
{
static const CSid sid(SecurityLocalSidAuthority, 1, SECURITY_LOCAL_RID);
return sid;
}
inline const CSid &CreatorOwner()
{
static const CSid sid(SecurityCreatorSidAuthority, 1, SECURITY_CREATOR_OWNER_RID);
return sid;
}
inline const CSid &CreatorGroup()
{
static const CSid sid(SecurityCreatorSidAuthority, 1, SECURITY_CREATOR_GROUP_RID);
return sid;
}
inline const CSid &CreatorOwnerServer()
{
static const CSid sid(SecurityCreatorSidAuthority, 1, SECURITY_CREATOR_OWNER_SERVER_RID);
return sid;
}
inline const CSid &CreatorGroupServer()
{
static const CSid sid(SecurityCreatorSidAuthority, 1, SECURITY_CREATOR_GROUP_SERVER_RID);
return sid;
}
// NT Authority
inline const CSid &Dialup()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_DIALUP_RID);
return sid;
}
inline const CSid &Network()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_NETWORK_RID);
return sid;
}
inline const CSid &Batch()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_BATCH_RID);
return sid;
}
inline const CSid &Interactive()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_INTERACTIVE_RID);
return sid;
}
inline const CSid &Service()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_SERVICE_RID);
return sid;
}
inline const CSid &AnonymousLogon()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_ANONYMOUS_LOGON_RID);
return sid;
}
inline const CSid &Proxy()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_PROXY_RID);
return sid;
}
inline const CSid &ServerLogon()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_SERVER_LOGON_RID);
return sid;
}
inline const CSid &Self()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_PRINCIPAL_SELF_RID);
return sid;
}
inline const CSid &AuthenticatedUser()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_AUTHENTICATED_USER_RID);
return sid;
}
inline const CSid &RestrictedCode()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_RESTRICTED_CODE_RID);
return sid;
}
inline const CSid &TerminalServer()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_TERMINAL_SERVER_RID);
return sid;
}
inline const CSid &System()
{
static const CSid sid(SecurityNTAuthority, 1, SECURITY_LOCAL_SYSTEM_RID);
return sid;
}
// NT Authority\BUILTIN
inline const CSid &Admins()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
return sid;
}
inline const CSid &Users()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS);
return sid;
}
inline const CSid &Guests()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS);
return sid;
}
inline const CSid &PowerUsers()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS);
return sid;
}
inline const CSid &AccountOps()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS);
return sid;
}
inline const CSid &SystemOps()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS);
return sid;
}
inline const CSid &PrintOps()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS);
return sid;
}
inline const CSid &BackupOps()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS);
return sid;
}
inline const CSid &Replicator()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR);
return sid;
}
inline const CSid &RasServers()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_RAS_SERVERS);
return sid;
}
inline const CSid &PreW2KAccess()
{
static const CSid sid(SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS);
return sid;
}
} // namespace Sids
inline CSid::CSid()
: m_pSid(NULL), m_SidNameUse(SidTypeInvalid)
{
}
inline CSid::CSid(LPCTSTR pszAccountName, LPCTSTR pszSystem)
: m_pSid(NULL), m_SidNameUse(SidTypeInvalid)
{
if(!LoadAccount(pszAccountName, pszSystem))
AtlThrowLastWin32();
}
inline CSid::CSid(const SID *pSid, LPCTSTR pszSystem)
: m_pSid(NULL), m_SidNameUse(SidTypeInvalid)
{
if(!LoadAccount(pSid, pszSystem))
AtlThrowLastWin32();
}
inline CSid::CSid(const SID_IDENTIFIER_AUTHORITY &IdentifierAuthority,
BYTE nSubAuthorityCount, ...)
: m_pSid(NULL), m_SidNameUse(SidTypeInvalid)
{
SID *pSid;
ATLASSERT(nSubAuthorityCount);
if(!nSubAuthorityCount)
AtlThrow(E_INVALIDARG);
pSid = static_cast<SID *>(_alloca(::GetSidLengthRequired(nSubAuthorityCount)));
if(!::InitializeSid(pSid,
const_cast<SID_IDENTIFIER_AUTHORITY *>(&IdentifierAuthority),
nSubAuthorityCount))
{
AtlThrowLastWin32();
}
va_list args;
va_start(args, nSubAuthorityCount);
for(UINT i = 0; i < nSubAuthorityCount; i++)
*::GetSidSubAuthority(pSid, i) = va_arg(args, DWORD);
va_end(args);
Copy(*pSid);
m_SidNameUse = SidTypeUnknown;
}
inline CSid::CSid(const CSid &rhs)
: m_SidNameUse(rhs.m_SidNameUse), m_pSid(NULL),
m_strAccountName(rhs.m_strAccountName), m_strDomain(rhs.m_strDomain),
m_strSid(rhs.m_strSid)
{
if(!rhs.IsValid())
AtlThrow(E_INVALIDARG);
DWORD dwLengthSid = ::GetLengthSid(rhs.m_pSid);
m_pSid = static_cast<SID *>(malloc(dwLengthSid));
if(!m_pSid)
AtlThrow(E_OUTOFMEMORY);
if(!::CopySid(dwLengthSid, m_pSid, rhs.m_pSid))
{
HRESULT hr = AtlHresultFromLastError();
free(m_pSid);
AtlThrow(hr);
}
}
inline CSid &CSid::operator=(const CSid &rhs)
{
if(this != &rhs)
{
if(!rhs.IsValid())
AtlThrow(E_INVALIDARG);
m_SidNameUse = rhs.m_SidNameUse;
m_strAccountName = rhs.m_strAccountName;
m_strDomain = rhs.m_strDomain;
m_strSid = rhs.m_strSid;
free(m_pSid);
DWORD dwLengthSid = ::GetLengthSid(rhs.m_pSid);
m_pSid = static_cast<SID *>(malloc(dwLengthSid));
if(!m_pSid)
AtlThrow(E_OUTOFMEMORY);
if(!::CopySid(dwLengthSid, m_pSid, rhs.m_pSid))
{
HRESULT hr = AtlHresultFromLastError();
free(m_pSid);
m_pSid = NULL;
AtlThrow(hr);
}
}
return *this;
}
inline CSid::CSid(const SID &rhs)
: m_pSid(NULL), m_SidNameUse(SidTypeInvalid)
{
Copy(rhs);
}
inline CSid &CSid::operator=(const SID &rhs)
{
if(m_pSid != &rhs)
{
Clear();
Copy(rhs);
m_SidNameUse = SidTypeUnknown;
}
return *this;
}
inline bool CSid::LoadAccount(LPCTSTR pszAccountName, LPCTSTR pszSystem)
{
// REVIEW
static const DWORD dwSidSize = offsetof(SID, SubAuthority) + SID_MAX_SUB_AUTHORITIES * sizeof(DWORD);
static const DWORD dwDomainSize = 128; // seems reasonable
BYTE byTmp[dwSidSize];
SID *pSid = reinterpret_cast<SID *>(byTmp);
TCHAR szDomain[dwDomainSize];
DWORD cbSid = dwSidSize, cbDomain = dwDomainSize;
BOOL bSuccess = ::LookupAccountName(pszSystem, pszAccountName, pSid, &cbSid, szDomain, &cbDomain, &m_SidNameUse);
if(bSuccess || ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
{
// LookupAccountName doesn't change cbSid on success (although it changes cbDomain)
if(bSuccess)
cbSid = ::GetLengthSid(pSid);
free(m_pSid);
m_pSid = static_cast<SID *>(malloc(cbSid));
if (m_pSid)
{
if(bSuccess)
{
if(::CopySid(cbSid, m_pSid, pSid))
{
m_strDomain = szDomain;
m_strAccountName = pszAccountName;
m_strSystem = pszSystem;
return true;
}
}
else
{
LPTSTR pszDomain = m_strDomain.GetBuffer(cbDomain);
bSuccess = ::LookupAccountName(pszSystem, pszAccountName, m_pSid, &cbSid,
pszDomain ,&cbDomain, &m_SidNameUse);
m_strDomain.ReleaseBuffer();
if(bSuccess)
{
m_strAccountName = pszAccountName;
m_strSystem = pszSystem;
return true;
}
}
}
}
Clear();
return false;
}
inline bool CSid::LoadAccount(const SID *pSid, LPCTSTR pszSystem)
{
ATLASSERT(pSid);
if(pSid)
_ATLTRY
{
m_strSystem = pszSystem;
Copy(*pSid);
return true;
}
_ATLCATCHALL()
{
Clear();
}
return false;
}
inline LPCTSTR CSid::AccountName() const
{
if(m_strAccountName.IsEmpty())
GetAccountNameAndDomain();
return m_strAccountName;
}
inline LPCTSTR CSid::Domain() const
{
if(m_strDomain.IsEmpty())
GetAccountNameAndDomain();
return m_strDomain;
}
inline LPCTSTR CSid::Sid() const
{
if(m_strSid.IsEmpty())
{
#if(_WIN32_WINNT >= 0x0500)
LPTSTR pszSid;
if(::ConvertSidToStringSid(m_pSid, &pszSid))
{
m_strSid = pszSid;
::LocalFree(pszSid);
}
#else
SID_IDENTIFIER_AUTHORITY *psia = ::GetSidIdentifierAuthority(m_pSid);
UINT i;
if(psia->Value[0] || psia->Value[1])
{
unsigned __int64 nAuthority = 0;
for(i = 0; i < 6; i++)
{
nAuthority <<= 8;
nAuthority |= psia->Value[i];
}
m_strSid.Format(_T("S-%d-%I64u"), SID_REVISION, nAuthority);
}
else
{
ULONG nAuthority = 0;
for(i = 2; i < 6; i++)
{
nAuthority <<= 8;
nAuthority |= psia->Value[i];
}
m_strSid.Format(_T("S-%d-%lu"), SID_REVISION, nAuthority);
}
UINT nSubAuthorityCount = *::GetSidSubAuthorityCount(m_pSid);
CString strTemp;
for(i = 0; i < nSubAuthorityCount; i++)
{
strTemp.Format(_T("-%lu"), *::GetSidSubAuthority(m_pSid, i));
m_strSid += strTemp;
}
#endif
}
return m_strSid;
}
inline void CSid::Clear()
{
m_SidNameUse = SidTypeInvalid;
m_strAccountName.Empty();
m_strDomain.Empty();
m_strSid.Empty();
m_strSystem.Empty();
free(m_pSid);
m_pSid = NULL;
}
inline void CSid::Copy(const SID &rhs)
{
// This function assumes everything is cleaned up/initialized
// (with the exception of m_strSystem).
// It does some sanity checking to prevent memory leaks, but
// you should clean up all members of CSid before calling this
// function. (i.e., results are unpredictable on error)
ATLASSERT(m_SidNameUse == SidTypeInvalid);
ATLASSERT(m_strAccountName.IsEmpty());
ATLASSERT(m_strDomain.IsEmpty());
ATLASSERT(m_strSid.IsEmpty());
SID *p = const_cast<SID *>(&rhs);
if(!::IsValidSid(p))
AtlThrow(E_INVALIDARG);
free(m_pSid);
DWORD dwLengthSid = ::GetLengthSid(p);
m_pSid = (SID *) malloc(dwLengthSid);
if(!m_pSid)
AtlThrow(E_OUTOFMEMORY);
if(!::CopySid(dwLengthSid, m_pSid, p))
{
HRESULT hr = AtlHresultFromLastError();
free(m_pSid);
m_pSid = NULL;
AtlThrow(hr);
}
}
inline void CSid::GetAccountNameAndDomain() const
{
// REVIEW: 32 large enough?
static const DWORD dwMax = 32; // seems reasonable
DWORD cbName = dwMax, cbDomain = dwMax;
TCHAR szName[dwMax], szDomain[dwMax];
if(::LookupAccountSid(m_strSystem, m_pSid, szName, &cbName, szDomain, &cbDomain, &m_SidNameUse))
{
m_strAccountName = szName;
m_strDomain = szDomain;
}
else
{
switch(::GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
{
LPTSTR pszName = m_strAccountName.GetBuffer(cbName);
LPTSTR pszDomain = m_strDomain.GetBuffer(cbDomain);
if (!::LookupAccountSid(m_strSystem, m_pSid, pszName, &cbName, pszDomain, &cbDomain, &m_SidNameUse))
{
AtlThrowLastWin32();
}
m_strAccountName.ReleaseBuffer();
m_strDomain.ReleaseBuffer();
break;
}
case ERROR_NONE_MAPPED:
m_strAccountName.Empty();
m_strDomain.Empty();
m_SidNameUse = SidTypeUnknown;
break;
default:
ATLASSERT(FALSE);
}
}
}
template<>
class CElementTraits< CSid > :
public CElementTraitsBase< CSid >
{
public:
static ULONG Hash( INARGTYPE t ) throw()
{
return( ULONG( ULONG_PTR( t.GetPSID() ) ) );
}
static int CompareElements( INARGTYPE element1, INARGTYPE element2 ) throw()
{
return( element1 == element2 );
}
static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 ) throw()
{
#if 0
if( element1 < element2 )
{
return( -1 );
}
else if( element1 == element2 )
{
return( 0 );
}
else
{
ATLASSERT( element1 > element2 );
return( 1 );
}
#else
element1;
element2;
ATLASSERT(false);
return 0;
#endif
}
};
//***************************************
// CAcl
// CAce
//
// CDacl
// CAccessAce
//
// CSacl
// CAuditAce
//***************************************
// **************************************************************
// ACLs
class CAcl
{
public:
CAcl() : m_pAcl(NULL), m_bNull(false), m_dwAclRevision(ACL_REVISION){}
virtual ~CAcl(){free(m_pAcl);}
CAcl(const CAcl &rhs) : m_pAcl(NULL), m_bNull(rhs.m_bNull),
m_dwAclRevision(rhs.m_dwAclRevision){}
CAcl &operator=(const CAcl &rhs)
{
if(this != &rhs)
{
free(m_pAcl);
m_pAcl = NULL;
m_bNull = rhs.m_bNull;
m_dwAclRevision = rhs.m_dwAclRevision;
}
return *this;
}
typedef CSimpleArray<ACCESS_MASK> CAccessMaskArray;
typedef CSimpleArray<BYTE> CAceTypeArray;
typedef CSimpleArray<BYTE> CAceFlagArray;
void GetAclEntries(CSid::CSidArray *pSids, CAccessMaskArray *pAccessMasks = NULL,
CAceTypeArray *pAceTypes = NULL, CAceFlagArray *pAceFlags = NULL) const;
bool RemoveAces(const CSid &rSid);
virtual UINT GetAceCount() const = 0;
virtual void RemoveAllAces() = 0;
const ACL *GetPACL() const;
operator const ACL *() const {return GetPACL();}
UINT GetLength() const;
void SetNull(){Dirty(); m_bNull = true;}
void SetEmpty(){Dirty(); m_bNull = false;}
bool IsNull() const {return m_bNull;}
bool IsEmpty() const {return !m_bNull && 0 == GetAceCount();}
private:
mutable ACL *m_pAcl;
bool m_bNull;
protected:
void Dirty(){free(m_pAcl); m_pAcl = NULL;}
class CAce
{
public:
CAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags)
: m_dwAccessMask(AccessMask), m_Sid(rSid), m_AceFlags(AceFlags), m_pAce(NULL){}
virtual ~CAce(){free(m_pAce);}
CAce(const CAce &rhs) : m_Sid(rhs.m_Sid), m_dwAccessMask(rhs.m_dwAccessMask),
m_AceFlags(rhs.m_AceFlags), m_pAce(NULL){}
CAce &operator=(const CAce &rhs)
{
if(this != &rhs)
{
m_Sid = rhs.m_Sid;
m_dwAccessMask = rhs.m_dwAccessMask;
m_AceFlags = rhs.m_AceFlags;
free(m_pAce);
m_pAce = NULL;
}
return *this;
}
virtual void *GetACE() const = 0;
virtual UINT GetLength() const = 0;
virtual BYTE AceType() const = 0;
virtual bool IsObjectAce() const {return false;}
ACCESS_MASK AccessMask() const
{return m_dwAccessMask;}
BYTE AceFlags() const
{return m_AceFlags;}
const CSid &Sid() const
{return m_Sid;}
void AddAccess(ACCESS_MASK AccessMask)
{m_dwAccessMask |= AccessMask; free(m_pAce); m_pAce = NULL;}
protected:
CSid m_Sid;
ACCESS_MASK m_dwAccessMask;
BYTE m_AceFlags;
mutable void *m_pAce;
};
virtual const CAce *GetAce(UINT nIndex) const = 0;
virtual void RemoveAce(UINT nIndex) = 0;
virtual void PrepareAcesForACL() const {}
DWORD m_dwAclRevision;
};
inline const ACL *CAcl::GetPACL() const
{
if(!m_pAcl && !m_bNull)
{
UINT nAclLength = sizeof(ACL);
const CAce *pAce;
UINT i;
const UINT nCount = GetAceCount();
for(i = 0; i < nCount; i++)
{
pAce = GetAce(i);
ATLASSERT(pAce);
if(pAce)
nAclLength += pAce->GetLength();
}
m_pAcl = static_cast<ACL *>(malloc(nAclLength));
if(!m_pAcl)
return NULL;
if(!::InitializeAcl(m_pAcl, nAclLength, m_dwAclRevision))
{
free(m_pAcl);
m_pAcl = NULL;
}
else
{
PrepareAcesForACL();
for(i = 0; i < nCount; i++)
{
pAce = GetAce(i);
ATLASSERT(pAce);
if(!pAce ||
!::AddAce(m_pAcl, m_dwAclRevision, MAXDWORD, pAce->GetACE(), pAce->GetLength()))
{
free(m_pAcl);
m_pAcl = NULL;
break;
}
}
}
}
return m_pAcl;
}
inline UINT CAcl::GetLength() const
{
ACL *pAcl = const_cast<ACL *>(GetPACL());
ACL_SIZE_INFORMATION AclSize;
ATLASSERT(pAcl);
if(!::GetAclInformation(pAcl, &AclSize, sizeof(AclSize), AclSizeInformation))
{
ATLASSERT(false);
return 0;
}
else
return AclSize.AclBytesInUse;
}
inline void CAcl::GetAclEntries(CSid::CSidArray *pSids, CAccessMaskArray *pAccessMasks,
CAceTypeArray *pAceTypes, CAceFlagArray *pAceFlags) const
{
ATLASSERT(pSids);
if(pSids)
{
pSids->RemoveAll();
if(pAccessMasks)
pAccessMasks->RemoveAll();
if(pAceTypes)
pAceTypes->RemoveAll();
if(pAceFlags)
pAceFlags->RemoveAll();
const CAce *pAce;
const UINT nCount = GetAceCount();
for(UINT i = 0; i < nCount; i++)
{
pAce = GetAce(i);
pSids->Add(pAce->Sid());
if(pAccessMasks)
pAccessMasks->Add(pAce->AccessMask());
if(pAceTypes)
pAceTypes->Add(pAce->AceType());
if(pAceFlags)
pAceFlags->Add(pAce->AceFlags());
}
}
}
inline bool CAcl::RemoveAces(const CSid &rSid)
{
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
bool bRet = false;
const CAce *pAce;
UINT i = 0;
while(i < GetAceCount())
{
pAce = GetAce(i);
if(rSid == pAce->Sid())
{
RemoveAce(i);
bRet = true;
}
else
i++;
}
if(bRet)
Dirty();
return bRet;
}
// ************************************************
// CDacl
class CDacl : public CAcl
{
public:
CDacl(){}
~CDacl(){CDacl::RemoveAllAces();}
CDacl(const ACL &rhs){Copy(rhs);}
CDacl &operator=(const ACL &rhs);
bool AddAllowedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags = 0);
bool AddDeniedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags = 0);
#if(_WIN32_WINNT >= 0x0500)
bool AddAllowedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType);
bool AddDeniedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType);
#endif
void RemoveAllAces();
UINT GetAceCount() const
{return m_Acl.GetSize();}
private:
void Copy(const ACL &rhs);
class CAccessAce : public CAcl::CAce
{
public:
CAccessAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags, bool bAllowAccess)
: CAce(rSid, AccessMask, AceFlags), m_bAllow(bAllowAccess){}
void *GetACE() const;
UINT GetLength() const
{return offsetof(ACCESS_ALLOWED_ACE, SidStart) + m_Sid.GetLength();}
BYTE AceType() const
{return (BYTE)(m_bAllow ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE);}
bool Allow() const {return m_bAllow;}
bool Inherited() const {return 0 != (m_AceFlags & INHERITED_ACE);}
protected:
bool m_bAllow;
};
#if(_WIN32_WINNT >= 0x0500)
class CAccessObjectAce : public CAccessAce
{
public:
CAccessObjectAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags, bool bAllowAccess,
const GUID *pObjectType, const GUID *pInheritedObjectType);
~CAccessObjectAce();
CAccessObjectAce(const CAccessObjectAce &rhs)
: CAccessAce(rhs), m_pObjectType(NULL), m_pInheritedObjectType(NULL){*this = rhs;}
CAccessObjectAce &operator=(const CAccessObjectAce &rhs);
void *GetACE() const;
UINT GetLength() const;
BYTE AceType() const
{return (BYTE)(m_bAllow ? ACCESS_ALLOWED_OBJECT_ACE_TYPE : ACCESS_DENIED_OBJECT_ACE_TYPE);}
bool IsObjectAce() const {return true;}
protected:
GUID *m_pObjectType, *m_pInheritedObjectType;
};
#endif
const CAcl::CAce *GetAce(UINT nIndex) const
{return m_Acl[nIndex];}
void RemoveAce(UINT nIndex);
void PrepareAcesForACL() const;
mutable CSimpleArray<CAccessAce *> m_Acl;
friend bool operator>(const CAccessAce &lhs, const CAccessAce &rhs)
{
// The order is:
// denied direct aces
// denied direct object aces
// allowed direct aces
// allowed direct object aces
// denied inherit aces
// denied inherit object aces
// allowed inherit aces
// allowed inherit object aces
// inherited aces are always "greater" than non-inherited aces
if(lhs.Inherited() && !rhs.Inherited())
return true;
if(!lhs.Inherited() && rhs.Inherited())
return false;
// if the aces are *both* either inherited or non-inherited, continue...
// allowed aces are always "greater" than denied aces (subject to above)
if(lhs.Allow() && !rhs.Allow())
return true;
if(!lhs.Allow() && rhs.Allow())
return false;
// if the aces are *both* either allowed or denied, continue...
// object aces are always "greater" than non-object aces (subject to above)
if(lhs.IsObjectAce() && !rhs.IsObjectAce())
return true;
if(!lhs.IsObjectAce() && rhs.IsObjectAce())
return false;
// aces are "equal" (e.g., both are access denied inherited object aces)
return false;
}
};
inline CDacl &CDacl::operator=(const ACL &rhs)
{
RemoveAllAces();
Copy(rhs);
return *this;
}
inline void CDacl::PrepareAcesForACL() const
{
// For a dacl, sort the aces
int i, j, h = 1;
const int nCount = m_Acl.GetSize();
CAccessAce *pAce;
while(h * 3 + 1 < nCount)
h = 3 * h + 1;
while(h > 0)
{
for(i = h - 1; i < nCount; i++)
{
pAce = m_Acl[i];
for(j = i; j >= h && *m_Acl[j - h] > *pAce; j -= h)
m_Acl[j] = m_Acl[j - h];
m_Acl[j] = pAce;
}
h /= 3;
}
}
inline void CDacl::Copy(const ACL &rhs)
{
ACL *pAcl = const_cast<ACL *>(&rhs);
ACL_SIZE_INFORMATION AclSizeInfo;
ACE_HEADER *pHeader;
CSid Sid;
ACCESS_MASK AccessMask;
CAccessAce *pAce;
Dirty();
if(!::GetAclInformation(pAcl, &AclSizeInfo, sizeof(AclSizeInfo), AclSizeInformation))
AtlThrowLastWin32();
for(DWORD i = 0; i < AclSizeInfo.AceCount; i++)
{
if(!::GetAce(pAcl, i, reinterpret_cast<void **>(&pHeader)))
AtlThrowLastWin32();
AccessMask = *reinterpret_cast<ACCESS_MASK *>
(reinterpret_cast<BYTE *>(pHeader) + sizeof(ACE_HEADER));
switch(pHeader->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
Sid = *reinterpret_cast<SID *>
(reinterpret_cast<BYTE *>(pHeader) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
ATLTRY(pAce = new CAccessAce(Sid, AccessMask, pHeader->AceFlags,
ACCESS_ALLOWED_ACE_TYPE == pHeader->AceType));
if (!pAce)
AtlThrow(E_OUTOFMEMORY);
if (!m_Acl.Add(pAce))
{
delete pAce;
AtlThrow(E_OUTOFMEMORY);
}
break;
#if(_WIN32_WINNT >= 0x0500)
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
GUID *pObjectType = NULL, *pInheritedObjectType = NULL;
BYTE *pb = reinterpret_cast<BYTE *>
(pHeader) + offsetof(ACCESS_ALLOWED_OBJECT_ACE, SidStart);
DWORD dwFlags = reinterpret_cast<ACCESS_ALLOWED_OBJECT_ACE *>(pHeader)->Flags;
if(dwFlags & ACE_OBJECT_TYPE_PRESENT)
{
pObjectType = reinterpret_cast<GUID *>
(reinterpret_cast<BYTE *>(pHeader) +
offsetof(ACCESS_ALLOWED_OBJECT_ACE, ObjectType));
}
else
pb -= sizeof(GUID);
if(dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
pInheritedObjectType = reinterpret_cast<GUID *>
(reinterpret_cast<BYTE *>(pHeader) +
(pObjectType ?
offsetof(ACCESS_ALLOWED_OBJECT_ACE, InheritedObjectType) :
offsetof(ACCESS_ALLOWED_OBJECT_ACE, ObjectType)));
}
else
pb -= sizeof(GUID);
Sid = *reinterpret_cast<SID *>(pb);
ATLTRY(pAce = new CAccessObjectAce(Sid, AccessMask, pHeader->AceFlags,
ACCESS_ALLOWED_OBJECT_ACE_TYPE == pHeader->AceType,
pObjectType, pInheritedObjectType));
if (!pAce)
AtlThrow(E_OUTOFMEMORY);
if (!m_Acl.Add(pAce))
{
delete pAce;
AtlThrow(E_OUTOFMEMORY);
}
break;
}
#endif
default:
// Wrong ACE type
ATLASSERT(false);
}
}
}
inline bool CDacl::AddAllowedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags)
{
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAccessAce *pAce = NULL;
ATLTRY(pAce = new CAccessAce(rSid, AccessMask, AceFlags, true));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
Dirty();
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CDacl::AddAllowedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType)
{
if(!pObjectType && !pInheritedObjectType)
return AddAllowedAce(rSid, AccessMask, AceFlags);
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAccessAce *pAce;
ATLTRY(pAce = new CAccessObjectAce(rSid, AccessMask, AceFlags, true,
pObjectType, pInheritedObjectType));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
m_dwAclRevision = ACL_REVISION_DS;
Dirty();
return true;
}
#endif
inline bool CDacl::AddDeniedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags)
{
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAccessAce *pAce = NULL;
ATLTRY(pAce = new CAccessAce(rSid, AccessMask, AceFlags, false));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
Dirty();
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CDacl::AddDeniedAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType)
{
if(!pObjectType && !pInheritedObjectType)
return AddDeniedAce(rSid, AccessMask, AceFlags);
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAccessAce *pAce;
ATLTRY(pAce = new CAccessObjectAce(rSid, AccessMask, AceFlags, false,
pObjectType, pInheritedObjectType));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
m_dwAclRevision = ACL_REVISION_DS;
Dirty();
return true;
}
#endif
inline void CDacl::RemoveAllAces()
{
const UINT nCount = GetAceCount();
for(UINT i = 0; i < nCount; i++)
delete GetAce(i);
m_Acl.RemoveAll();
Dirty();
}
inline void CDacl::RemoveAce(UINT nIndex)
{
delete GetAce(nIndex);
m_Acl.RemoveAt(nIndex);
}
inline void *CDacl::CAccessAce::GetACE() const
{
C_ASSERT(sizeof(ACCESS_ALLOWED_ACE) == sizeof(ACCESS_DENIED_ACE));
C_ASSERT(offsetof(ACCESS_ALLOWED_ACE, Header)==offsetof(ACCESS_DENIED_ACE, Header));
C_ASSERT(offsetof(ACCESS_ALLOWED_ACE, Mask)==offsetof(ACCESS_DENIED_ACE, Mask));
C_ASSERT(offsetof(ACCESS_ALLOWED_ACE, SidStart)==offsetof(ACCESS_DENIED_ACE, SidStart));
if(!m_pAce)
{
UINT nLength = GetLength();
ACCESS_ALLOWED_ACE *pAce = static_cast<ACCESS_ALLOWED_ACE *>(malloc(nLength));
if(!pAce)
return NULL;
memset(pAce, 0x00, nLength);
pAce->Header.AceSize = static_cast<WORD>(nLength);
pAce->Header.AceFlags = m_AceFlags;
pAce->Header.AceType = AceType();
pAce->Mask = m_dwAccessMask;
ATLASSERT(nLength-offsetof(ACCESS_ALLOWED_ACE, SidStart) >= m_Sid.GetLength());
memcpy(&pAce->SidStart, m_Sid.GetPSID(), m_Sid.GetLength());
m_pAce = pAce;
}
return m_pAce;
}
#if(_WIN32_WINNT >= 0x0500)
inline CDacl::CAccessObjectAce::CAccessObjectAce(const CSid &rSid, ACCESS_MASK AccessMask,
BYTE AceFlags, bool bAllowAccess,
const GUID *pObjectType,
const GUID *pInheritedObjectType) :
CAccessAce(rSid, AccessMask, AceFlags, bAllowAccess),
m_pObjectType(NULL),
m_pInheritedObjectType(NULL)
{
if(pObjectType)
{
ATLTRY(m_pObjectType = new GUID(*pObjectType));
if(!m_pObjectType)
AtlThrow(E_OUTOFMEMORY);
}
if(pInheritedObjectType)
{
ATLTRY(m_pInheritedObjectType = new GUID(*pInheritedObjectType));
if(!m_pInheritedObjectType)
{
delete m_pObjectType;
m_pObjectType = NULL;
AtlThrow(E_OUTOFMEMORY);
}
}
}
inline CDacl::CAccessObjectAce::~CAccessObjectAce()
{
delete m_pObjectType;
delete m_pInheritedObjectType;
}
inline CDacl::CAccessObjectAce &CDacl::CAccessObjectAce::operator=(const CAccessObjectAce &rhs)
{
if(this != &rhs)
{
CAccessAce::operator=(rhs);
if(rhs.m_pObjectType)
{
if(!m_pObjectType)
{
ATLTRY(m_pObjectType = new GUID);
if(!m_pObjectType)
AtlThrow(E_OUTOFMEMORY);
}
*m_pObjectType = *rhs.m_pObjectType;
}
else
{
delete m_pObjectType;
m_pObjectType = NULL;
}
if(rhs.m_pInheritedObjectType)
{
if(!m_pInheritedObjectType)
{
ATLTRY(m_pInheritedObjectType = new GUID);
if(!m_pInheritedObjectType)
{
delete m_pObjectType;
m_pObjectType = NULL;
AtlThrow(E_OUTOFMEMORY);
}
}
*m_pInheritedObjectType = *rhs.m_pInheritedObjectType;
}
else
{
delete m_pInheritedObjectType;
m_pInheritedObjectType = NULL;
}
}
return *this;
}
inline UINT CDacl::CAccessObjectAce::GetLength() const
{
UINT nLength = offsetof(ACCESS_ALLOWED_OBJECT_ACE, SidStart);
if(!m_pObjectType)
nLength -= sizeof(GUID);
if(!m_pInheritedObjectType)
nLength -= sizeof(GUID);
nLength += m_Sid.GetLength();
return nLength;
}
inline void *CDacl::CAccessObjectAce::GetACE() const
{
C_ASSERT(sizeof(ACCESS_ALLOWED_OBJECT_ACE) == sizeof(ACCESS_DENIED_OBJECT_ACE));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, Header)==offsetof(ACCESS_DENIED_OBJECT_ACE, Header));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, Mask)==offsetof(ACCESS_DENIED_OBJECT_ACE, Mask));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, Flags)==offsetof(ACCESS_DENIED_OBJECT_ACE, Flags));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, ObjectType)==offsetof(ACCESS_DENIED_OBJECT_ACE, ObjectType));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, InheritedObjectType)==offsetof(ACCESS_DENIED_OBJECT_ACE, InheritedObjectType));
C_ASSERT(offsetof(ACCESS_ALLOWED_OBJECT_ACE, SidStart)==offsetof(ACCESS_DENIED_OBJECT_ACE, SidStart));
if(!m_pAce)
{
UINT nLength = GetLength();
ACCESS_ALLOWED_OBJECT_ACE *pAce = static_cast<ACCESS_ALLOWED_OBJECT_ACE *>(malloc(nLength));
if(!pAce)
return NULL;
memset(pAce, 0x00, nLength);
pAce->Header.AceSize = static_cast<WORD>(nLength);
pAce->Header.AceFlags = m_AceFlags;
pAce->Header.AceType = AceType();
pAce->Mask = m_dwAccessMask;
pAce->Flags = 0;
BYTE *pb = (reinterpret_cast<BYTE *>(pAce)) + offsetof(ACCESS_ALLOWED_OBJECT_ACE, SidStart);
if(!m_pObjectType)
pb -= sizeof(GUID);
else
{
pAce->ObjectType = *m_pObjectType;
pAce->Flags |= ACE_OBJECT_TYPE_PRESENT;
}
if(!m_pInheritedObjectType)
pb -= sizeof(GUID);
else
{
if(m_pObjectType)
pAce->InheritedObjectType = *m_pInheritedObjectType;
else
pAce->ObjectType = *m_pInheritedObjectType;
pAce->Flags |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
}
ATLASSERT(size_t(pb - reinterpret_cast<BYTE *>(pAce)) >= m_Sid.GetLength());
memcpy(pb, m_Sid.GetPSID(), m_Sid.GetLength());
m_pAce = pAce;
}
return m_pAce;
}
#endif // _WIN32_WINNT
//******************************************
// CSacl
class CSacl : public CAcl
{
public:
CSacl(){}
~CSacl(){CSacl::RemoveAllAces();}
CSacl(const ACL &rhs) {Copy(rhs);}
CSacl &operator=(const ACL &rhs);
bool AddAuditAce(const CSid &rSid, ACCESS_MASK AccessMask,
bool bSuccess, bool bFailure, BYTE AceFlags = 0);
#if(_WIN32_WINNT >= 0x0500)
bool AddAuditAce(const CSid &rSid, ACCESS_MASK AccessMask,
bool bSuccess, bool bFailure, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType);
#endif
void RemoveAllAces();
UINT GetAceCount() const
{return m_Acl.GetSize();}
private:
void Copy(const ACL &rhs);
class CAuditAce : public CAcl::CAce
{
public:
CAuditAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
bool bAuditSuccess, bool bAuditFailure)
: CAce(rSid, AccessMask, AceFlags),
m_bSuccess(bAuditSuccess), m_bFailure(bAuditFailure){}
void *GetACE() const;
UINT GetLength() const
{return offsetof(SYSTEM_AUDIT_ACE, SidStart) + m_Sid.GetLength();}
BYTE AceType() const
{return SYSTEM_AUDIT_ACE_TYPE;}
protected:
bool m_bSuccess, m_bFailure;
};
#if(_WIN32_WINNT >= 0x0500)
class CAuditObjectAce : public CAuditAce
{
public:
CAuditObjectAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
bool bAuditSuccess, bool bAuditFailure,
const GUID *pObjectType, const GUID *pInheritedObjectType);
~CAuditObjectAce();
CAuditObjectAce(const CAuditObjectAce &rhs)
: CAuditAce(rhs), m_pObjectType(NULL), m_pInheritedObjectType(NULL){*this = rhs;}
CAuditObjectAce &operator=(const CAuditObjectAce &rhs);
void *GetACE() const;
UINT GetLength() const;
BYTE AceType() const
{return SYSTEM_AUDIT_OBJECT_ACE_TYPE;}
bool IsObjectAce() const {return true;}
protected:
GUID *m_pObjectType, *m_pInheritedObjectType;
};
#endif
POSITION GetHeadAce() const;
const CAce *GetAce(UINT nIndex) const
{return m_Acl[nIndex];}
void RemoveAce(UINT nIndex);
CSimpleArray<CAuditAce *> m_Acl;
};
inline CSacl &CSacl::operator=(const ACL &rhs)
{
RemoveAllAces();
Copy(rhs);
return *this;
}
inline void CSacl::Copy(const ACL &rhs)
{
ACL *pAcl = const_cast<ACL *>(&rhs);
ACL_SIZE_INFORMATION AclSizeInfo;
ACE_HEADER *pHeader;
CSid Sid;
ACCESS_MASK AccessMask;
bool bSuccess, bFailure;
CAuditAce *pAce;
Dirty();
if(!::GetAclInformation(pAcl, &AclSizeInfo, sizeof(AclSizeInfo), AclSizeInformation))
AtlThrowLastWin32();
for(DWORD i = 0; i < AclSizeInfo.AceCount; i++)
{
if(!::GetAce(pAcl, i, reinterpret_cast<void **>(&pHeader)))
AtlThrowLastWin32();
AccessMask = *reinterpret_cast<ACCESS_MASK *>
(reinterpret_cast<BYTE *>(pHeader) + sizeof(ACE_HEADER));
bSuccess = 0 != (pHeader->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG);
bFailure = 0 != (pHeader->AceFlags & FAILED_ACCESS_ACE_FLAG);
switch(pHeader->AceType)
{
case SYSTEM_AUDIT_ACE_TYPE:
Sid = *reinterpret_cast<SID *>
(reinterpret_cast<BYTE *>(pHeader) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
ATLTRY(pAce = new CAuditAce(Sid, AccessMask, pHeader->AceFlags, bSuccess, bFailure));
if (!pAce)
AtlThrow(E_OUTOFMEMORY);
if (!m_Acl.Add(pAce))
{
delete pAce;
AtlThrow(E_OUTOFMEMORY);
}
break;
#if(_WIN32_WINNT >= 0x0500)
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
GUID *pObjectType = NULL, *pInheritedObjectType = NULL;
BYTE *pb = reinterpret_cast<BYTE *>
(pHeader) + offsetof(SYSTEM_AUDIT_OBJECT_ACE, SidStart);
DWORD dwFlags = reinterpret_cast<SYSTEM_AUDIT_OBJECT_ACE *>(pHeader)->Flags;
if(dwFlags & ACE_OBJECT_TYPE_PRESENT)
{
pObjectType = reinterpret_cast<GUID *>
(reinterpret_cast<BYTE *>(pHeader) +
offsetof(SYSTEM_AUDIT_OBJECT_ACE, ObjectType));
}
else
pb -= sizeof(GUID);
if(dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
{
pInheritedObjectType = reinterpret_cast<GUID *>
(reinterpret_cast<BYTE *>(pHeader) +
(pObjectType ?
offsetof(SYSTEM_AUDIT_OBJECT_ACE, InheritedObjectType) :
offsetof(SYSTEM_AUDIT_OBJECT_ACE, ObjectType)));
}
else
pb -= sizeof(GUID);
Sid = *reinterpret_cast<SID *>(pb);
ATLTRY(pAce = new CAuditObjectAce(Sid, AccessMask, pHeader->AceFlags,
bSuccess, bFailure, pObjectType, pInheritedObjectType));
if(!pAce)
AtlThrow(E_OUTOFMEMORY);
if (!m_Acl.Add(pAce))
{
delete pAce;
AtlThrow(E_OUTOFMEMORY);
}
break;
}
#endif
default:
// Wrong ACE type
ATLASSERT(false);
}
}
}
inline bool CSacl::AddAuditAce(const CSid &rSid, ACCESS_MASK AccessMask,
bool bSuccess, bool bFailure, BYTE AceFlags)
{
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAuditAce *pAce;
ATLTRY(pAce = new CAuditAce(rSid, AccessMask, AceFlags, bSuccess, bFailure));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
Dirty();
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CSacl::AddAuditAce(const CSid &rSid, ACCESS_MASK AccessMask,
bool bSuccess, bool bFailure, BYTE AceFlags,
const GUID *pObjectType, const GUID *pInheritedObjectType)
{
if(!pObjectType && !pInheritedObjectType)
return AddAuditAce(rSid, AccessMask, bSuccess, bFailure, AceFlags);
ATLASSERT(rSid.IsValid());
if(IsNull() || !rSid.IsValid())
return false;
CAuditAce *pAce;
ATLTRY(pAce = new CAuditObjectAce(rSid, AccessMask, AceFlags, bSuccess,
bFailure, pObjectType, pInheritedObjectType));
if(!pAce)
return false;
if (!m_Acl.Add(pAce))
{
delete pAce;
return false;
}
m_dwAclRevision = ACL_REVISION_DS;
Dirty();
return true;
}
#endif
inline void CSacl::RemoveAllAces()
{
const UINT nCount = GetAceCount();
for(UINT i = 0; i < nCount; i++)
delete GetAce(i);
m_Acl.RemoveAll();
Dirty();
}
inline void CSacl::RemoveAce(UINT nIndex)
{
delete GetAce(nIndex);
m_Acl.RemoveAt(nIndex);
}
inline void *CSacl::CAuditAce::GetACE() const
{
if(!m_pAce)
{
UINT nLength = GetLength();
SYSTEM_AUDIT_ACE *pAce = static_cast<SYSTEM_AUDIT_ACE *>(malloc(nLength));
if(!pAce)
return NULL;
memset(pAce, 0x00, nLength);
pAce->Header.AceSize = static_cast<WORD>(nLength);
pAce->Header.AceFlags = m_AceFlags;
pAce->Header.AceType = AceType();;
pAce->Mask = m_dwAccessMask;
ATLASSERT(nLength-offsetof(SYSTEM_AUDIT_ACE, SidStart) >= m_Sid.GetLength());
memcpy(&pAce->SidStart, m_Sid.GetPSID(), m_Sid.GetLength());
if(m_bSuccess)
pAce->Header.AceFlags |= SUCCESSFUL_ACCESS_ACE_FLAG;
else
pAce->Header.AceFlags &= ~SUCCESSFUL_ACCESS_ACE_FLAG;
if(m_bFailure)
pAce->Header.AceFlags |= FAILED_ACCESS_ACE_FLAG;
else
pAce->Header.AceFlags &= ~FAILED_ACCESS_ACE_FLAG;
m_pAce = pAce;
}
return m_pAce;
}
#if(_WIN32_WINNT >= 0x0500)
inline CSacl::CAuditObjectAce::CAuditObjectAce(const CSid &rSid, ACCESS_MASK AccessMask, BYTE AceFlags,
bool bAuditSuccess, bool bAuditFailure, const GUID *pObjectType, const GUID *pInheritedObjectType)
: CAuditAce(rSid, AccessMask, AceFlags, bAuditSuccess, bAuditFailure)
{
if(pObjectType)
{
ATLTRY(m_pObjectType = new GUID(*pObjectType));
if(!m_pObjectType)
AtlThrow(E_OUTOFMEMORY);
}
if(pInheritedObjectType)
{
ATLTRY(m_pInheritedObjectType = new GUID(*pInheritedObjectType));
if(!m_pInheritedObjectType)
{
delete m_pObjectType;
m_pObjectType = NULL;
AtlThrow(E_OUTOFMEMORY);
}
}
}
inline CSacl::CAuditObjectAce::~CAuditObjectAce()
{
delete m_pObjectType;
delete m_pInheritedObjectType;
}
inline CSacl::CAuditObjectAce &CSacl::CAuditObjectAce::operator=(const CAuditObjectAce &rhs)
{
if(this != &rhs)
{
CAuditAce::operator=(rhs);
if(rhs.m_pObjectType)
{
if(!m_pObjectType)
{
ATLTRY(m_pObjectType = new GUID);
if(!m_pObjectType)
AtlThrow(E_OUTOFMEMORY);
}
*m_pObjectType = *rhs.m_pObjectType;
}
else
{
delete m_pObjectType;
m_pObjectType = NULL;
}
if(rhs.m_pInheritedObjectType)
{
if(!m_pInheritedObjectType)
{
ATLTRY(m_pInheritedObjectType = new GUID);
if(!m_pInheritedObjectType)
{
delete m_pObjectType;
m_pObjectType = NULL;
AtlThrow(E_OUTOFMEMORY);
}
}
*m_pInheritedObjectType = *rhs.m_pInheritedObjectType;
}
else
{
delete m_pInheritedObjectType;
m_pInheritedObjectType = NULL;
}
}
return *this;
}
inline UINT CSacl::CAuditObjectAce::GetLength() const
{
UINT nLength = offsetof(SYSTEM_AUDIT_OBJECT_ACE, SidStart);
if(!m_pObjectType)
nLength -= sizeof(GUID);
if(!m_pInheritedObjectType)
nLength -= sizeof(GUID);
nLength += m_Sid.GetLength();
return nLength;
}
inline void *CSacl::CAuditObjectAce::GetACE() const
{
if(!m_pAce)
{
UINT nLength = GetLength();
SYSTEM_AUDIT_OBJECT_ACE *pAce = static_cast<SYSTEM_AUDIT_OBJECT_ACE *>(malloc(nLength));
if(!pAce)
return NULL;
memset(pAce, 0x00, nLength);
pAce->Header.AceType = SYSTEM_AUDIT_OBJECT_ACE_TYPE;
pAce->Header.AceSize = static_cast<WORD>(nLength);
pAce->Header.AceFlags = m_AceFlags;
pAce->Mask = m_dwAccessMask;
pAce->Flags = 0;
if(m_bSuccess)
pAce->Header.AceFlags |= SUCCESSFUL_ACCESS_ACE_FLAG;
else
pAce->Header.AceFlags &= ~SUCCESSFUL_ACCESS_ACE_FLAG;
if(m_bFailure)
pAce->Header.AceFlags |= FAILED_ACCESS_ACE_FLAG;
else
pAce->Header.AceFlags &= ~FAILED_ACCESS_ACE_FLAG;
BYTE *pb = ((BYTE *) pAce) + offsetof(SYSTEM_AUDIT_OBJECT_ACE, SidStart);
if(!m_pObjectType)
pb -= sizeof(GUID);
else
{
pAce->ObjectType = *m_pObjectType;
pAce->Flags |= ACE_OBJECT_TYPE_PRESENT;
}
if(!m_pInheritedObjectType)
pb -= sizeof(GUID);
else
{
if(m_pObjectType)
pAce->InheritedObjectType = *m_pInheritedObjectType;
else
pAce->ObjectType = *m_pInheritedObjectType;
pAce->Flags |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
}
ATLASSERT(size_t(pb - reinterpret_cast<BYTE*>(pAce)) >= m_Sid.GetLength());
memcpy(pb, m_Sid.GetPSID(), m_Sid.GetLength());
m_pAce = pAce;
}
return m_pAce;
}
#endif
//******************************************
// CSecurityDesc
class CSecurityDesc
{
public:
CSecurityDesc() : m_pSecurityDescriptor(NULL){}
virtual ~CSecurityDesc() {Clear();}
CSecurityDesc(const CSecurityDesc &rhs);
CSecurityDesc &operator=(const CSecurityDesc &rhs);
CSecurityDesc(const SECURITY_DESCRIPTOR &rhs);
CSecurityDesc &operator=(const SECURITY_DESCRIPTOR &rhs);
#if(_WIN32_WINNT >= 0x0500)
bool FromString(LPCTSTR pstr);
bool ToString(CString *pstr,
SECURITY_INFORMATION si =
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION) const;
#endif
bool SetOwner(const CSid &Sid, bool bDefaulted = false);
bool SetGroup(const CSid &Sid, bool bDefaulted = false);
bool SetDacl(const CDacl &Dacl, bool bDefaulted = false);
bool SetDacl(bool bPresent, bool bDefaulted = false);
bool SetSacl(const CSacl &Sacl, bool bDefaulted = false);
bool GetOwner(CSid *pSid, bool *pbDefaulted = NULL) const;
bool GetGroup(CSid *pSid, bool *pbDefaulted = NULL) const;
bool GetDacl(CDacl *pDacl, bool *pbPresent = NULL, bool *pbDefaulted = NULL) const;
bool GetSacl(CSacl *pSacl, bool *pbPresent = NULL, bool *pbDefaulted = NULL) const;
bool IsDaclDefaulted() const;
bool IsDaclPresent() const;
bool IsGroupDefaulted() const;
bool IsOwnerDefaulted() const;
bool IsSaclDefaulted() const;
bool IsSaclPresent() const;
bool IsSelfRelative() const;
// Only meaningful on Win2k or better
bool IsDaclAutoInherited() const;
bool IsDaclProtected() const;
bool IsSaclAutoInherited() const;
bool IsSaclProtected() const;
const SECURITY_DESCRIPTOR *GetPSECURITY_DESCRIPTOR() const
{return m_pSecurityDescriptor;}
operator const SECURITY_DESCRIPTOR *() const {return GetPSECURITY_DESCRIPTOR();}
bool GetSECURITY_DESCRIPTOR(SECURITY_DESCRIPTOR *pSD, LPDWORD lpdwBufferLength);
bool GetControl(SECURITY_DESCRIPTOR_CONTROL *psdc) const;
#if(_WIN32_WINNT >= 0x0500)
bool SetControl(SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);
#endif
bool MakeSelfRelative();
bool MakeAbsolute();
protected:
virtual void Clear();
bool AllocateAndInitializeSecurityDescriptor();
void Init(const SECURITY_DESCRIPTOR &rhs);
SECURITY_DESCRIPTOR *m_pSecurityDescriptor;
};
class CSecurityAttributes : public SECURITY_ATTRIBUTES
{
public:
CSecurityAttributes()
{nLength = 0; lpSecurityDescriptor = NULL; bInheritHandle = FALSE;}
explicit CSecurityAttributes(const CSecurityDesc &rSecurityDescriptor, bool bInheritHandle = false) :
m_SecurityDescriptor(rSecurityDescriptor)
{
Set(m_SecurityDescriptor, bInheritHandle);
}
void Set(const CSecurityDesc &rSecurityDescriptor, bool bInheritHandle = false)
{
m_SecurityDescriptor = rSecurityDescriptor;
nLength = sizeof(SECURITY_ATTRIBUTES);
lpSecurityDescriptor = const_cast<SECURITY_DESCRIPTOR *>
(m_SecurityDescriptor.GetPSECURITY_DESCRIPTOR());
this->bInheritHandle = bInheritHandle;
}
protected:
CSecurityDesc m_SecurityDescriptor;
};
inline CSecurityDesc::CSecurityDesc(const CSecurityDesc &rhs)
: m_pSecurityDescriptor(NULL)
{
if(rhs.m_pSecurityDescriptor)
Init(*rhs.m_pSecurityDescriptor);
}
inline CSecurityDesc &CSecurityDesc::operator=(const CSecurityDesc &rhs)
{
if(this != &rhs)
{
Clear();
if(rhs.m_pSecurityDescriptor)
Init(*rhs.m_pSecurityDescriptor);
}
return *this;
}
inline CSecurityDesc::CSecurityDesc(const SECURITY_DESCRIPTOR &rhs)
: m_pSecurityDescriptor(NULL)
{
Init(rhs);
}
inline CSecurityDesc &CSecurityDesc::operator=(const SECURITY_DESCRIPTOR &rhs)
{
if(m_pSecurityDescriptor != &rhs)
{
Clear();
Init(rhs);
}
return *this;
}
inline void CSecurityDesc::Init(const SECURITY_DESCRIPTOR &rhs)
{
SECURITY_DESCRIPTOR *pSD = const_cast<SECURITY_DESCRIPTOR *>(&rhs);
DWORD dwRev, dwLen = ::GetSecurityDescriptorLength(pSD);
m_pSecurityDescriptor = static_cast<SECURITY_DESCRIPTOR *>(malloc(dwLen));
if(!m_pSecurityDescriptor)
AtlThrow(E_OUTOFMEMORY);
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!::GetSecurityDescriptorControl(pSD, &sdc, &dwRev))
{
HRESULT hr = AtlHresultFromLastError();
free(m_pSecurityDescriptor);
m_pSecurityDescriptor = NULL;
AtlThrow(hr);
}
if(sdc & SE_SELF_RELATIVE)
memcpy(m_pSecurityDescriptor, pSD, dwLen);
else
{
if(!::MakeSelfRelativeSD(pSD, m_pSecurityDescriptor, &dwLen))
{
HRESULT hr = AtlHresultFromLastError();
free(m_pSecurityDescriptor);
m_pSecurityDescriptor = NULL;
AtlThrow(hr);
}
}
}
inline void CSecurityDesc::Clear()
{
if(m_pSecurityDescriptor)
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(GetControl(&sdc) && !(sdc & SE_SELF_RELATIVE))
{
PSID pOwner, pGroup;
ACL *pDacl, *pSacl;
BOOL bDefaulted, bPresent;
::GetSecurityDescriptorOwner(m_pSecurityDescriptor, &pOwner, &bDefaulted);
free(pOwner);
::GetSecurityDescriptorGroup(m_pSecurityDescriptor, &pGroup, &bDefaulted);
free(pGroup);
::GetSecurityDescriptorDacl(m_pSecurityDescriptor, &bPresent, &pDacl, &bDefaulted);
if(bPresent)
free(pDacl);
::GetSecurityDescriptorSacl(m_pSecurityDescriptor, &bPresent, &pSacl, &bDefaulted);
if(bPresent)
free(pSacl);
}
free(m_pSecurityDescriptor);
m_pSecurityDescriptor = NULL;
}
}
inline bool CSecurityDesc::MakeSelfRelative()
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!m_pSecurityDescriptor || !GetControl(&sdc))
return false;
if(sdc & SE_SELF_RELATIVE)
return true;
SECURITY_DESCRIPTOR *pSD;
DWORD dwLen = 0;
::MakeSelfRelativeSD(m_pSecurityDescriptor, NULL, &dwLen);
if(::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return false;
pSD = static_cast<SECURITY_DESCRIPTOR *>(malloc(dwLen));
if(!pSD)
return false;
if(!::MakeSelfRelativeSD(m_pSecurityDescriptor, pSD, &dwLen))
{
free(pSD);
return false;
}
Clear();
m_pSecurityDescriptor = pSD;
return true;
}
inline bool CSecurityDesc::MakeAbsolute()
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!m_pSecurityDescriptor || !GetControl(&sdc))
return false;
if(!(sdc & SE_SELF_RELATIVE))
return true;
SECURITY_DESCRIPTOR *pSD;
SID *pOwner, *pGroup;
ACL *pDacl, *pSacl;
DWORD dwSD, dwOwner, dwGroup, dwDacl, dwSacl;
dwSD = dwOwner = dwGroup = dwDacl = dwSacl = 0;
::MakeAbsoluteSD(m_pSecurityDescriptor, NULL, &dwSD, NULL, &dwDacl,
NULL, &dwSacl, NULL, &dwOwner, NULL, &dwGroup);
if(::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return false;
pSD = static_cast<SECURITY_DESCRIPTOR *>(malloc(dwSD));
pOwner = static_cast<SID *>(dwOwner ? malloc(dwOwner) : NULL);
pGroup = static_cast<SID *>(dwGroup ? malloc(dwGroup) : NULL);
pDacl = static_cast<ACL *>(dwDacl ? malloc(dwDacl) : NULL);
pSacl = static_cast<ACL *>(dwSacl ? malloc(dwSacl) : NULL);
if(!::MakeAbsoluteSD(m_pSecurityDescriptor,
pSD, &dwSD,
pDacl, &dwDacl,
pSacl, &dwSacl,
pOwner, &dwOwner,
pGroup, &dwGroup))
{
free(pSD);
free(pOwner);
free(pGroup);
free(pDacl);
free(pSacl);
return false;
}
Clear();
m_pSecurityDescriptor = pSD;
return true;
}
inline bool CSecurityDesc::AllocateAndInitializeSecurityDescriptor()
{
// m_pSecurityDescriptor should be NULL.
ATLASSERT(!m_pSecurityDescriptor);
m_pSecurityDescriptor = static_cast<SECURITY_DESCRIPTOR *>(malloc(sizeof(SECURITY_DESCRIPTOR)));
if(!m_pSecurityDescriptor)
return false;
if(!::InitializeSecurityDescriptor(m_pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
{
free(m_pSecurityDescriptor);
m_pSecurityDescriptor = NULL;
return false;
}
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CSecurityDesc::FromString(LPCTSTR pstr)
{
SECURITY_DESCRIPTOR *pSD;
if(!::ConvertStringSecurityDescriptorToSecurityDescriptor(pstr, SDDL_REVISION_1,
(PSECURITY_DESCRIPTOR *) &pSD, NULL))
{
return false;
}
*this = *pSD;
::LocalFree(pSD);
return true;
}
inline bool CSecurityDesc::ToString(CString *pstr, SECURITY_INFORMATION si) const
{
ATLASSERT(pstr);
if(!pstr || !m_pSecurityDescriptor)
return false;
LPTSTR pszStringSecurityDescriptor;
if(!::ConvertSecurityDescriptorToStringSecurityDescriptor(m_pSecurityDescriptor,
SDDL_REVISION_1,
si,
&pszStringSecurityDescriptor,
NULL))
{
return false;
}
*pstr = pszStringSecurityDescriptor;
::LocalFree(pszStringSecurityDescriptor);
return true;
}
#endif
inline bool CSecurityDesc::GetSECURITY_DESCRIPTOR(SECURITY_DESCRIPTOR *pSD, LPDWORD lpdwBufferLength)
{
ATLASSERT(lpdwBufferLength);
if(!lpdwBufferLength)
return false;
if(!MakeAbsolute())
return false;
return 0 != ::MakeSelfRelativeSD(m_pSecurityDescriptor, pSD, lpdwBufferLength);
}
inline bool CSecurityDesc::SetOwner(const CSid &Sid, bool bDefaulted)
{
if(m_pSecurityDescriptor && !MakeAbsolute())
return false;
PSID pNewOwner, pOldOwner;
if(m_pSecurityDescriptor)
{
BOOL bDefaulted;
if(!::GetSecurityDescriptorOwner(m_pSecurityDescriptor, &pOldOwner, &bDefaulted))
return false;
}
else
{
if(!AllocateAndInitializeSecurityDescriptor())
return false;
pOldOwner = NULL;
}
if(!Sid.IsValid())
return false;
UINT nSidLength = Sid.GetLength();
pNewOwner = malloc(nSidLength);
if(!pNewOwner)
return false;
if(!::CopySid(nSidLength, pNewOwner, const_cast<SID *>(Sid.GetPSID())) ||
!::SetSecurityDescriptorOwner(m_pSecurityDescriptor, pNewOwner, bDefaulted))
{
free(pNewOwner);
return false;
}
free(pOldOwner);
return true;
}
inline bool CSecurityDesc::SetGroup(const CSid &Sid, bool bDefaulted)
{
if(m_pSecurityDescriptor && !MakeAbsolute())
return false;
PSID pNewGroup, pOldGroup;
if(m_pSecurityDescriptor)
{
BOOL bDefaulted;
if(!::GetSecurityDescriptorGroup(m_pSecurityDescriptor, &pOldGroup, &bDefaulted))
return false;
}
else
{
if(!AllocateAndInitializeSecurityDescriptor())
return false;
pOldGroup = NULL;
}
if(!Sid.IsValid())
return false;
UINT nSidLength = Sid.GetLength();
pNewGroup = malloc(nSidLength);
if(!pNewGroup)
return false;
if(!::CopySid(nSidLength, pNewGroup, const_cast<SID *>(Sid.GetPSID())) ||
!::SetSecurityDescriptorGroup(m_pSecurityDescriptor, pNewGroup, bDefaulted))
{
free(pNewGroup);
return false;
}
free(pOldGroup);
return true;
}
inline bool CSecurityDesc::SetDacl(bool bPresent, bool bDefaulted)
{
if(m_pSecurityDescriptor && !MakeAbsolute())
return false;
PACL pOldDacl = NULL;
if(m_pSecurityDescriptor)
{
BOOL bDefaulted, bPresent;
if(!::GetSecurityDescriptorDacl(m_pSecurityDescriptor, &bPresent, &pOldDacl, &bDefaulted))
return false;
}
else
if(!AllocateAndInitializeSecurityDescriptor())
return false;
#ifdef _DEBUG
if(bPresent)
ATLTRACE(atlTraceSecurity, 2, _T("Caution: Setting Dacl to Null\n"));
#endif
if(!::SetSecurityDescriptorDacl(m_pSecurityDescriptor, bPresent, NULL, bDefaulted))
return false;
free(pOldDacl);
return true;
}
inline bool CSecurityDesc::SetDacl(const CDacl &Dacl, bool bDefaulted)
{
if(m_pSecurityDescriptor && !MakeAbsolute())
return false;
PACL pNewDacl, pOldDacl = NULL;
if(m_pSecurityDescriptor)
{
BOOL bDefaulted, bPresent;
if(!::GetSecurityDescriptorDacl(m_pSecurityDescriptor, &bPresent, &pOldDacl, &bDefaulted))
return false;
}
else if(!AllocateAndInitializeSecurityDescriptor())
return false;
if(Dacl.IsNull() || Dacl.IsEmpty())
pNewDacl = NULL;
else
{
UINT nAclLength = Dacl.GetLength();
if(!nAclLength)
return false;
pNewDacl = static_cast<ACL *>(malloc(nAclLength));
if(!pNewDacl)
return false;
memcpy(pNewDacl, Dacl.GetPACL(), nAclLength);
}
#ifdef _DEBUG
if(Dacl.IsNull())
ATLTRACE(atlTraceSecurity, 2, _T("Caution: Setting Dacl to Null\n"));
#endif
if(!::SetSecurityDescriptorDacl(m_pSecurityDescriptor, Dacl.IsNull() || pNewDacl, pNewDacl, bDefaulted))
{
free(pNewDacl);
return false;
}
free(pOldDacl);
return true;
}
inline bool CSecurityDesc::SetSacl(const CSacl &Sacl, bool bDefaulted)
{
if(m_pSecurityDescriptor && !MakeAbsolute())
return false;
PACL pNewSacl, pOldSacl = NULL;
if(m_pSecurityDescriptor)
{
BOOL bDefaulted, bPresent;
if(!::GetSecurityDescriptorSacl(m_pSecurityDescriptor, &bPresent, &pOldSacl, &bDefaulted))
return false;
}
else if(!AllocateAndInitializeSecurityDescriptor())
return false;
if(Sacl.IsNull() || Sacl.IsEmpty())
pNewSacl = NULL;
else
{
UINT nAclLength = Sacl.GetLength();
if(!nAclLength)
return false;
pNewSacl = static_cast<ACL *>(malloc(nAclLength));
if(!pNewSacl)
return false;
memcpy(pNewSacl, Sacl.GetPACL(), nAclLength);
}
if(!::SetSecurityDescriptorSacl(m_pSecurityDescriptor, Sacl.IsNull() || pNewSacl, pNewSacl, bDefaulted))
{
free(pNewSacl);
return false;
}
free(pOldSacl);
return true;
}
inline bool CSecurityDesc::GetOwner(CSid *pSid, bool *pbDefaulted) const
{
ATLASSERT(pSid);
SID *pOwner;
BOOL bDefaulted;
if(!pSid || !m_pSecurityDescriptor ||
!::GetSecurityDescriptorOwner(m_pSecurityDescriptor, (PSID *) &pOwner, &bDefaulted))
{
return false;
}
*pSid = *pOwner;
if(pbDefaulted)
*pbDefaulted = 0 != bDefaulted;
return true;
}
inline bool CSecurityDesc::GetGroup(CSid *pSid, bool *pbDefaulted) const
{
ATLASSERT(pSid);
SID *pGroup;
BOOL bDefaulted;
if(!pSid || !m_pSecurityDescriptor ||
!::GetSecurityDescriptorGroup(m_pSecurityDescriptor, (PSID *) &pGroup, &bDefaulted))
{
return false;
}
*pSid = *pGroup;
if(pbDefaulted)
*pbDefaulted = 0 != bDefaulted;
return true;
}
inline bool CSecurityDesc::GetDacl(CDacl *pDacl, bool *pbPresent, bool *pbDefaulted) const
{
ACL *pAcl;
BOOL bPresent, bDefaulted;
if(!m_pSecurityDescriptor ||
!::GetSecurityDescriptorDacl(m_pSecurityDescriptor, &bPresent, &pAcl, &bDefaulted) ||
!bPresent)
{
return false;
}
if(pDacl)
{
if(bPresent)
{
if(pAcl)
*pDacl = *pAcl;
else
pDacl->SetNull();
}
else
pDacl->SetEmpty();
}
if(pbPresent)
*pbPresent = 0 != bPresent;
if(pbDefaulted)
*pbDefaulted = 0 != bDefaulted;
return true;
}
inline bool CSecurityDesc::GetSacl(CSacl *pSacl, bool *pbPresent, bool *pbDefaulted) const
{
ACL *pAcl;
BOOL bPresent, bDefaulted;
if(!m_pSecurityDescriptor ||
!::GetSecurityDescriptorSacl(m_pSecurityDescriptor, &bPresent, &pAcl, &bDefaulted) ||
!bPresent)
{
return false;
}
if(pSacl)
{
if(bPresent)
{
if(pAcl)
*pSacl = *pAcl;
else
pSacl->SetNull();
}
else
pSacl->SetEmpty();
}
if(pbPresent)
*pbPresent = 0 != bPresent;
if(pbDefaulted)
*pbDefaulted = 0 != bDefaulted;
return true;
}
inline bool CSecurityDesc::IsDaclDefaulted() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return (sdc & SE_DACL_PRESENT) &&
(sdc & SE_DACL_DEFAULTED);
}
inline bool CSecurityDesc::IsDaclPresent() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_DACL_PRESENT);
}
inline bool CSecurityDesc::IsGroupDefaulted() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_GROUP_DEFAULTED);
}
inline bool CSecurityDesc::IsOwnerDefaulted() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return (sdc & SE_OWNER_DEFAULTED);
}
inline bool CSecurityDesc::IsSaclDefaulted() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return (sdc & SE_SACL_PRESENT) &&
(sdc & SE_SACL_DEFAULTED);
}
inline bool CSecurityDesc::IsSaclPresent() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_SACL_PRESENT);
}
inline bool CSecurityDesc::IsSelfRelative() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_SELF_RELATIVE);
}
inline bool CSecurityDesc::IsDaclAutoInherited() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_DACL_AUTO_INHERITED);
}
inline bool CSecurityDesc::IsDaclProtected() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_DACL_PROTECTED);
}
inline bool CSecurityDesc::IsSaclAutoInherited() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_SACL_AUTO_INHERITED);
}
inline bool CSecurityDesc::IsSaclProtected() const
{
SECURITY_DESCRIPTOR_CONTROL sdc;
if(!GetControl(&sdc))
return false;
return 0 != (sdc & SE_SACL_PROTECTED);
}
inline bool CSecurityDesc::GetControl(SECURITY_DESCRIPTOR_CONTROL *psdc) const
{
ATLASSERT(psdc);
if(!psdc)
return false;
DWORD dwRev;
*psdc = 0;
if(!m_pSecurityDescriptor ||
!::GetSecurityDescriptorControl(m_pSecurityDescriptor, psdc, &dwRev))
{
return false;
}
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CSecurityDesc::SetControl(SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet)
{
return 0 != ::SetSecurityDescriptorControl(m_pSecurityDescriptor,
ControlBitsOfInterest, ControlBitsToSet);
}
#endif
template<>
class CSimpleArrayEqualHelper<LUID>
{
public:
static bool IsEqual(const LUID& l1, const LUID& l2)
{
return l1.HighPart == l2.HighPart && l1.LowPart == l2.LowPart;
}
};
template<>
class CElementTraits< LUID > :
public CElementTraitsBase< LUID >
{
public:
typedef const LUID& INARGTYPE;
typedef LUID& OUTARGTYPE;
static ULONG Hash( INARGTYPE luid )
{
return luid.HighPart ^ luid.LowPart;
}
static BOOL CompareElements( INARGTYPE element1, INARGTYPE element2 )
{
return CSimpleArrayEqualHelper<LUID>::IsEqual(element1, element2);
}
static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 )
{
_LARGE_INTEGER li1, li2;
li1.LowPart = element1.LowPart;
li1.HighPart = element1.HighPart;
li2.LowPart = element2.LowPart;
li2.HighPart = element2.HighPart;
if( li1.QuadPart > li2.QuadPart )
return( 1 );
else if( li1.QuadPart < li2.QuadPart )
return( -1 );
return( 0 );
}
};
typedef CSimpleArray<LUID> CLUIDArray;
//******************************************************
// CTokenPrivileges
class CTokenPrivileges
{
public:
CTokenPrivileges() : m_bDirty(true), m_pTokenPrivileges(NULL){}
virtual ~CTokenPrivileges() {free(m_pTokenPrivileges);}
CTokenPrivileges(const CTokenPrivileges &rhs);
CTokenPrivileges &operator=(const CTokenPrivileges &rhs);
CTokenPrivileges(const TOKEN_PRIVILEGES &rPrivileges) :
m_pTokenPrivileges(NULL) {AddPrivileges(rPrivileges);}
CTokenPrivileges &operator=(const TOKEN_PRIVILEGES &rPrivileges)
{m_TokenPrivileges.RemoveAll(); AddPrivileges(rPrivileges); return *this;}
void Add(const TOKEN_PRIVILEGES &rPrivileges)
{AddPrivileges(rPrivileges);}
bool Add(LPCTSTR pszPrivilege, bool bEnable);
typedef CSimpleArray<CString> CNames;
typedef CSimpleArray<DWORD> CAttributes;
bool LookupPrivilege(LPCTSTR pszPrivilege, DWORD *pdwAttributes = NULL) const;
void GetNamesAndAttributes(CNames *pNames, CAttributes *pAttributes = NULL) const;
void GetDisplayNames(CNames *pDisplayNames) const;
void GetLuidsAndAttributes(CLUIDArray *pPrivileges, CAttributes *pAttributes = NULL) const;
bool Delete(LPCTSTR pszPrivilege);
void DeleteAll(){m_TokenPrivileges.RemoveAll(); m_bDirty = true;}
UINT GetCount() const {return (UINT) m_TokenPrivileges.GetCount();}
UINT GetLength() const
{return offsetof(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * GetCount();}
const TOKEN_PRIVILEGES *GetPTOKEN_PRIVILEGES() const;
operator const TOKEN_PRIVILEGES *() const {return GetPTOKEN_PRIVILEGES();}
private:
typedef CAtlMap<LUID, DWORD> Map;
Map m_TokenPrivileges;
mutable TOKEN_PRIVILEGES *m_pTokenPrivileges;
bool m_bDirty;
void AddPrivileges(const TOKEN_PRIVILEGES &rPrivileges);
};
inline CTokenPrivileges::CTokenPrivileges(const CTokenPrivileges &rhs)
: m_pTokenPrivileges(NULL), m_bDirty(true)
{
const Map::CPair *pPair;
POSITION pos = rhs.m_TokenPrivileges.GetStartPosition();
while(pos)
{
pPair = rhs.m_TokenPrivileges.GetNext(pos);
m_TokenPrivileges.SetAt(pPair->m_key, pPair->m_value);
}
}
inline CTokenPrivileges &CTokenPrivileges::operator=(const CTokenPrivileges &rhs)
{
if(this != &rhs)
{
m_TokenPrivileges.RemoveAll();
const Map::CPair *pPair;
POSITION pos = rhs.m_TokenPrivileges.GetStartPosition();
while(pos)
{
pPair = rhs.m_TokenPrivileges.GetNext(pos);
m_TokenPrivileges.SetAt(pPair->m_key, pPair->m_value);
}
m_bDirty = true;
}
return *this;
}
inline bool CTokenPrivileges::Add(LPCTSTR pszPrivilege, bool bEnable)
{
LUID_AND_ATTRIBUTES la;
if(!::LookupPrivilegeValue(NULL, pszPrivilege, &la.Luid))
return false;
la.Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
m_TokenPrivileges.SetAt(la.Luid, la.Attributes);
m_bDirty = true;
return true;
}
inline bool CTokenPrivileges::Delete(LPCTSTR pszPrivilege)
{
LUID Luid;
if(!::LookupPrivilegeValue(NULL, pszPrivilege, &Luid))
return false;
if(!m_TokenPrivileges.RemoveKey(Luid))
return false;
m_bDirty = true;
return true;
}
inline const TOKEN_PRIVILEGES *CTokenPrivileges::GetPTOKEN_PRIVILEGES() const
{
if(m_bDirty)
{
free(m_pTokenPrivileges);
m_pTokenPrivileges = NULL;
if(m_TokenPrivileges.GetCount())
{
m_pTokenPrivileges = static_cast<TOKEN_PRIVILEGES *>(malloc(GetLength()));
if(!m_pTokenPrivileges)
return NULL;
m_pTokenPrivileges->PrivilegeCount = (DWORD) GetCount();
UINT i = 0;
POSITION pos = m_TokenPrivileges.GetStartPosition();
const Map::CPair *pPair;
while(pos)
{
pPair = m_TokenPrivileges.GetNext(pos);
m_pTokenPrivileges->Privileges[i].Luid = pPair->m_key;
m_pTokenPrivileges->Privileges[i].Attributes = pPair->m_value;
i++;
}
}
}
return m_pTokenPrivileges;
}
inline void CTokenPrivileges::AddPrivileges(const TOKEN_PRIVILEGES &rPrivileges)
{
m_bDirty = true;
for(UINT i = 0; i < rPrivileges.PrivilegeCount; i++)
m_TokenPrivileges.SetAt(
rPrivileges.Privileges[i].Luid, rPrivileges.Privileges[i].Attributes);
}
inline bool CTokenPrivileges::LookupPrivilege(LPCTSTR pszPrivilege,
DWORD *pdwAttributes) const
{
DWORD dwAttributes;
LUID luid;
if(!::LookupPrivilegeValue(NULL, pszPrivilege, &luid))
return false;
if(m_TokenPrivileges.Lookup(luid, dwAttributes))
{
if(pdwAttributes)
*pdwAttributes = dwAttributes;
return true;
}
return false;
}
inline void CTokenPrivileges::GetNamesAndAttributes(CNames *pNames,
CAttributes *pAttributes) const
{
ATLASSERT(pNames);
if(pNames)
{
LPTSTR psz = NULL;
DWORD cbName = 0, cbTmp;
const Map::CPair *pPair;
pNames->RemoveAll();
if(pAttributes)
pAttributes->RemoveAll();
POSITION pos = m_TokenPrivileges.GetStartPosition();
while(pos)
{
pPair = m_TokenPrivileges.GetNext(pos);
cbTmp = cbName;
if(!::LookupPrivilegeName(NULL, const_cast<LUID *>(&pPair->m_key), psz, &cbTmp))
if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
delete[] psz;
ATLTRY(psz = new TCHAR[cbTmp + 1]);
if(!psz)
{
pNames->RemoveAll();
if(pAttributes)
pAttributes->RemoveAll();
AtlThrow(E_OUTOFMEMORY);
}
cbName = cbTmp;
if(!::LookupPrivilegeName(NULL, const_cast<LUID *>(&pPair->m_key), psz, &cbTmp))
break;
}
else
break;
pNames->Add(psz);
if(pAttributes)
pAttributes->Add(pPair->m_value);
}
delete[] psz;
if(pos)
{
pNames->RemoveAll();
if(pAttributes)
pAttributes->RemoveAll();
}
}
}
inline void CTokenPrivileges::GetDisplayNames(CNames *pDisplayNames) const
{
ATLASSERT(pDisplayNames);
if(pDisplayNames)
{
DWORD dwLang, cbTmp, cbDisplayName = 0;
LPTSTR psz = NULL;
CNames Names;
int i;
GetNamesAndAttributes(&Names);
pDisplayNames->RemoveAll();
for(i = 0; i < Names.GetSize(); i++)
{
cbTmp = cbDisplayName;
if(!::LookupPrivilegeDisplayName(NULL, Names[i], psz, &cbTmp, &dwLang))
{
if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
delete[] psz;
ATLTRY(psz = new TCHAR[cbTmp + 1]);
if(!psz)
{
pDisplayNames->RemoveAll();
AtlThrow(E_OUTOFMEMORY);
}
cbDisplayName = cbTmp;
if(!::LookupPrivilegeDisplayName(NULL, Names[i], psz, &cbTmp, &dwLang))
break;
}
else
break;
}
pDisplayNames->Add(psz);
}
delete[] psz;
if(i != Names.GetSize())
pDisplayNames->RemoveAll();
}
}
inline void CTokenPrivileges::GetLuidsAndAttributes(CLUIDArray *pLuids,
CAttributes *pAttributes) const
{
ATLASSERT(pLuids);
if(pLuids)
{
const Map::CPair *pPair;
pLuids->RemoveAll();
if(pAttributes)
pAttributes->RemoveAll();
POSITION pos = m_TokenPrivileges.GetStartPosition();
while(pos)
{
pPair = m_TokenPrivileges.GetNext(pos);
pLuids->Add(pPair->m_key);
if(pAttributes)
pAttributes->Add(pPair->m_value);
}
}
}
//******************************************************
// CTokenGroups
class CTokenGroups
{
public:
CTokenGroups() : m_pTokenGroups(NULL), m_bDirty(true){}
virtual ~CTokenGroups() {free(m_pTokenGroups);}
CTokenGroups(const CTokenGroups &rhs);
CTokenGroups &operator=(const CTokenGroups &rhs);
CTokenGroups(const TOKEN_GROUPS &rhs) :
m_pTokenGroups(NULL) {AddTokenGroups(rhs);}
CTokenGroups &operator=(const TOKEN_GROUPS &rhs)
{m_TokenGroups.RemoveAll(); AddTokenGroups(rhs); return *this;}
void Add(const TOKEN_GROUPS &rTokenGroups)
{AddTokenGroups(rTokenGroups);}
void Add(const CSid &rSid, DWORD dwAttributes)
{m_TokenGroups.SetAt(rSid, dwAttributes); m_bDirty = true;}
bool LookupSid(const CSid &rSid, DWORD *pdwAttributes = NULL) const;
void GetSidsAndAttributes(CSid::CSidArray *pSids,
CSimpleArray<DWORD> *pAttributes = NULL) const;
bool Delete(const CSid &rSid) {return m_TokenGroups.RemoveKey(rSid);}
void DeleteAll(){m_TokenGroups.RemoveAll(); m_bDirty = true;}
UINT GetCount() const {return (UINT) m_TokenGroups.GetCount();}
UINT GetLength() const
{return UINT(offsetof(TOKEN_GROUPS, Groups) +
sizeof(SID_AND_ATTRIBUTES) * m_TokenGroups.GetCount());}
const TOKEN_GROUPS *GetPTOKEN_GROUPS() const;
operator const TOKEN_GROUPS *() const {return GetPTOKEN_GROUPS();}
private:
class CTGElementTraits :
public CElementTraitsBase< CSid >
{
public:
static UINT Hash(const CSid &sid)
{return sid.GetSubAuthority(sid.GetSubAuthorityCount() - 1);}
static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) throw()
{
return( element1 == element2 );
}
};
typedef CAtlMap<CSid, DWORD, CTGElementTraits> Map;
Map m_TokenGroups;
mutable TOKEN_GROUPS *m_pTokenGroups;
mutable bool m_bDirty;
void AddTokenGroups(const TOKEN_GROUPS &rTokenGroups);
};
inline CTokenGroups::CTokenGroups(const CTokenGroups &rhs)
: m_pTokenGroups(NULL), m_bDirty(true)
{
const Map::CPair *pPair;
POSITION pos = rhs.m_TokenGroups.GetStartPosition();
while(pos)
{
pPair = rhs.m_TokenGroups.GetNext(pos);
m_TokenGroups.SetAt(pPair->m_key, pPair->m_value);
}
}
inline CTokenGroups &CTokenGroups::operator=(const CTokenGroups &rhs)
{
if(this != &rhs)
{
m_TokenGroups.RemoveAll();
const Map::CPair *pPair;
POSITION pos = rhs.m_TokenGroups.GetStartPosition();
while(pos)
{
pPair = rhs.m_TokenGroups.GetNext(pos);
m_TokenGroups.SetAt(pPair->m_key, pPair->m_value);
}
m_bDirty = true;
}
return *this;
}
inline const TOKEN_GROUPS *CTokenGroups::GetPTOKEN_GROUPS() const
{
if(m_bDirty)
{
free(m_pTokenGroups);
m_pTokenGroups = NULL;
if(m_TokenGroups.GetCount())
{
m_pTokenGroups = static_cast<TOKEN_GROUPS *>(malloc(GetLength()));
if(!m_pTokenGroups)
return NULL;
m_pTokenGroups->GroupCount = (DWORD) m_TokenGroups.GetCount();
UINT i = 0;
POSITION pos = m_TokenGroups.GetStartPosition();
const Map::CPair *pPair;
while(pos)
{
// REVIEW: see if there's a way to make sure that no one mucks with this
// sid... (unlikely that anyone would, but possible)
pPair = m_TokenGroups.GetNext(pos);
m_pTokenGroups->Groups[i].Sid = const_cast<SID *>(pPair->m_key.GetPSID());
m_pTokenGroups->Groups[i].Attributes = pPair->m_value;
i++;
}
}
}
return m_pTokenGroups;
}
inline void CTokenGroups::AddTokenGroups(const TOKEN_GROUPS &rTokenGroups)
{
m_bDirty = true;
for(UINT i = 0; i < rTokenGroups.GroupCount; i++)
m_TokenGroups.SetAt(
CSid(static_cast<SID *>(rTokenGroups.Groups[i].Sid)),
rTokenGroups.Groups[i].Attributes);
}
inline bool CTokenGroups::LookupSid(const CSid &rSid, DWORD *pdwAttributes) const
{
DWORD dwAttributes;
if(m_TokenGroups.Lookup(rSid, dwAttributes))
{
if(pdwAttributes)
*pdwAttributes = dwAttributes;
return true;
}
return false;
}
inline void CTokenGroups::GetSidsAndAttributes(CSid::CSidArray *pSids,
CSimpleArray<DWORD> *pAttributes) const
{
ATLASSERT(pSids);
if(pSids)
{
const Map::CPair *pPair;
pSids->RemoveAll();
if(pAttributes)
pAttributes->RemoveAll();
POSITION pos = m_TokenGroups.GetStartPosition();
while(pos)
{
pPair = m_TokenGroups.GetNext(pos);
pSids->Add(pPair->m_key);
if(pAttributes)
pAttributes->Add(pPair->m_value);
}
}
}
// *************************************
// CAccessToken
class CAccessToken
{
public:
CAccessToken() : m_hToken(NULL), m_hProfile(NULL), m_pRevert(NULL){}
// REVIEW: should privileges that have been enabled be automatically
// disabled in the dtor of CAccessToken?
virtual ~CAccessToken();
bool Attach(HANDLE hToken, bool bDuplicate = false,
HANDLE hSrcProcess = NULL, HANDLE hDestProcess = NULL, bool bInherit = false);
HANDLE Detach()
{HANDLE hToken = m_hToken; m_hToken = NULL; Clear(); return hToken;}
HANDLE GetHandle() const {return m_hToken;}
HANDLE HKeyCurrentUser() const {return m_hProfile;}
// Privileges
bool EnablePrivilege(LPCTSTR pszPrivilege, CTokenPrivileges *pPreviousState = NULL);
bool EnablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges,
CTokenPrivileges *pPreviousState = NULL);
bool DisablePrivilege(LPCTSTR pszPrivilege, CTokenPrivileges *pPreviousState = NULL);
bool DisablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges, CTokenPrivileges *pPreviousState = NULL);
bool EnableDisablePrivileges(const CTokenPrivileges &rPrivilenges,
CTokenPrivileges *pPreviousState = NULL);
bool PrivilegeCheck(PPRIVILEGE_SET RequiredPrivileges, bool *pbResult) const;
bool GetLogonSid(CSid *pSid) const;
bool GetTokenId(LUID *pluid) const;
bool GetLogonSessionId(LUID *pluid) const;
bool CheckTokenMembership(const CSid &rSid, bool *pbIsMember) const;
#if(_WIN32_WINNT >= 0x0500)
bool IsTokenRestricted() const {return 0 != ::IsTokenRestricted(m_hToken);}
#endif
// Token Information
protected:
template<typename RET_T, typename INFO_T>
void InfoTypeToRetType(RET_T *pRet, const INFO_T &rWork) const
{ATLASSERT(pRet); *pRet = rWork;}
template<>
void InfoTypeToRetType(CDacl *pRet, const TOKEN_DEFAULT_DACL &rWork) const
{ATLASSERT(pRet); *pRet = *rWork.DefaultDacl;}
template<>
void InfoTypeToRetType(CSid *pRet, const TOKEN_OWNER &rWork) const
{ATLASSERT(pRet); *pRet = *static_cast<SID *>(rWork.Owner);}
template<>
void InfoTypeToRetType(CSid *pRet, const TOKEN_PRIMARY_GROUP &rWork) const
{ATLASSERT(pRet); *pRet = *static_cast<SID *>(rWork.PrimaryGroup);}
template<>
void InfoTypeToRetType(CSid *pRet, const TOKEN_USER &rWork) const
{ATLASSERT(pRet); *pRet = *static_cast<SID *>(rWork.User.Sid);}
template<typename RET_T, typename INFO_T>
bool GetInfoConvert(RET_T *pRet, TOKEN_INFORMATION_CLASS TokenClass, INFO_T *pWork = NULL) const
{
ATLASSERT(pRet);
if(!pRet)
return false;
DWORD dwLen;
::GetTokenInformation(m_hToken, TokenClass, NULL, 0, &dwLen);
if(::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return false;
pWork = static_cast<INFO_T *>(_alloca(dwLen));
if(!::GetTokenInformation(m_hToken, TokenClass, pWork, dwLen, &dwLen))
return false;
InfoTypeToRetType(pRet, *pWork);
return true;
}
template<typename RET_T>
bool GetInfo(RET_T *pRet, TOKEN_INFORMATION_CLASS TokenClass) const
{
ATLASSERT(pRet);
if(!pRet)
return false;
DWORD dwLen;
if(!::GetTokenInformation(m_hToken, TokenClass, pRet, sizeof(RET_T), &dwLen))
return false;
return true;
}
public:
bool GetDefaultDacl(CDacl *pDacl) const
{return GetInfoConvert<CDacl, TOKEN_DEFAULT_DACL>(pDacl, TokenDefaultDacl);}
bool GetGroups(CTokenGroups *pGroups) const
{return GetInfoConvert<CTokenGroups, TOKEN_GROUPS>(pGroups, TokenGroups);}
bool GetImpersonationLevel(SECURITY_IMPERSONATION_LEVEL *pImpersonationLevel) const
{return GetInfo<SECURITY_IMPERSONATION_LEVEL>(pImpersonationLevel, TokenImpersonationLevel);}
bool GetOwner(CSid *pSid) const
{return GetInfoConvert<CSid, TOKEN_OWNER>(pSid, TokenOwner);}
bool GetPrimaryGroup(CSid *pSid) const
{return GetInfoConvert<CSid, TOKEN_PRIMARY_GROUP>(pSid, TokenPrimaryGroup);}
bool GetPrivileges(CTokenPrivileges *pPrivileges) const
{return GetInfoConvert<CTokenPrivileges, TOKEN_PRIVILEGES>(pPrivileges, TokenPrivileges);}
bool GetTerminalServicesSessionId(DWORD *pdwSessionId) const
{return GetInfo<DWORD>(pdwSessionId, TokenSessionId);}
bool GetSource(TOKEN_SOURCE *pSource) const
{return GetInfo<TOKEN_SOURCE>(pSource, TokenSource);}
bool GetStatistics(TOKEN_STATISTICS *pStatistics) const
{return GetInfo<TOKEN_STATISTICS>(pStatistics, TokenStatistics);}
bool GetType(TOKEN_TYPE *pType) const
{return GetInfo<TOKEN_TYPE>(pType, TokenType);}
bool GetUser(CSid *pSid) const
{return GetInfoConvert<CSid, TOKEN_USER>(pSid, TokenUser);}
bool SetOwner(const CSid &rSid);
bool SetPrimaryGroup(const CSid &rSid);
bool SetDefaultDacl(const CDacl &rDacl);
bool CreateImpersonationToken(CAccessToken *pImp,
SECURITY_IMPERSONATION_LEVEL sil = SecurityImpersonation) const;
bool CreatePrimaryToken(CAccessToken *pPri,
DWORD dwDesiredAccess = MAXIMUM_ALLOWED,
const CSecurityAttributes *pTokenAttributes = NULL) const;
#if(_WIN32_WINNT >= 0x0500)
bool CreateRestrictedToken(CAccessToken *pRestrictedToken,
const CTokenGroups &SidsToDisable, const CTokenGroups &SidsToRestrict,
const CTokenPrivileges &PrivilegesToDelete = CTokenPrivileges()) const;
#endif
// Token API type functions
bool GetProcessToken(DWORD dwDesiredAccess, HANDLE hProcess = NULL);
bool GetThreadToken(DWORD dwDesiredAccess, HANDLE hThread = NULL, bool bOpenAsSelf = true);
bool GetEffectiveToken(DWORD dwDesiredAccess);
bool OpenThreadToken(DWORD dwDesiredAccess,
bool bImpersonate = false, bool bOpenAsSelf = true,
SECURITY_IMPERSONATION_LEVEL sil = SecurityImpersonation);
#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
bool OpenCOMClientToken(DWORD dwDesiredAccess,
bool bImpersonate = false, bool bOpenAsSelf = true);
#endif //(_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
bool OpenNamedPipeClientToken(HANDLE hPipe, DWORD dwDesiredAccess,
bool bImpersonate = false, bool bOpenAsSelf = true);
bool OpenRPCClientToken(RPC_BINDING_HANDLE BindingHandle, DWORD dwDesiredAccess,
bool bImpersonate = false, bool bOpenAsSelf = true);
bool ImpersonateLoggedOnUser() const;
bool Impersonate(HANDLE hThread = NULL) const;
bool Revert(HANDLE hThread = NULL) const;
bool LoadUserProfile();
HANDLE GetProfile() const {return m_hProfile;}
// Must hold Tcb privilege
bool LogonUser(
LPCTSTR pszUserName, LPCTSTR pszDomain, LPCTSTR pszPassword,
DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE,
DWORD dwLogonProvider = LOGON32_PROVIDER_DEFAULT);
// Must hold AssignPrimaryToken (unless restricted token) and
// IncreaseQuota privileges
bool CreateProcessAsUser(
LPCTSTR pApplicationName, LPTSTR pCommandLine,
LPPROCESS_INFORMATION pProcessInformation,
LPSTARTUPINFO pStartupInfo,
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS,
bool bLoadProfile = false,
const CSecurityAttributes *pProcessAttributes = NULL,
const CSecurityAttributes *pThreadAttributes = NULL,
bool bInherit = false,
LPCTSTR pCurrentDirectory = NULL);
protected:
bool EnableDisablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges,
bool bEnable, CTokenPrivileges *pPreviousState);
void CheckImpersonation() const;
virtual void Clear();
HANDLE m_hToken, m_hProfile;
private:
// REVIEW: need copy?
CAccessToken(const CAccessToken &rhs);
CAccessToken &operator=(const CAccessToken &rhs);
class CRevert
{
public:
virtual bool Revert() = 0;
};
class CRevertToSelf : public CRevert
{
public:
bool Revert(){return 0 != ::RevertToSelf();}
};
#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
class CCoRevertToSelf : public CRevert
{
public:
bool Revert(){return SUCCEEDED(::CoRevertToSelf());}
};
#endif //(_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
class CRpcRevertToSelfEx : public CRevert
{
public:
CRpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle)
: m_BindingHandle(BindingHandle){}
bool Revert(){return RPC_S_OK == ::RpcRevertToSelfEx(m_BindingHandle);}
private:
RPC_BINDING_HANDLE m_BindingHandle;
};
mutable CRevert *m_pRevert;
};
// *************************************
// CAccessToken implementation
inline CAccessToken::~CAccessToken()
{
Clear();
}
inline bool CAccessToken::Attach(HANDLE hToken, bool bDuplicate,
HANDLE hSrcProcess, HANDLE hDestProcess, bool bInherit)
{
ATLASSERT(hToken && hToken != m_hToken);
if(hToken && hToken != m_hToken)
{
Clear();
if(!bDuplicate)
{
m_hToken = hToken;
return true;
}
else
{
if(!hSrcProcess)
hSrcProcess = ::GetCurrentProcess();
if(!hDestProcess)
hDestProcess = ::GetCurrentProcess();
return 0 != ::DuplicateHandle(hSrcProcess, hToken, hDestProcess, &m_hToken,
0, bInherit, DUPLICATE_SAME_ACCESS);
}
}
return false;
}
inline void CAccessToken::Clear()
{
if(m_hProfile)
{
ATLASSERT(m_hToken);
if(m_hToken)
::UnloadUserProfile(m_hToken, m_hProfile);
m_hProfile = NULL;
}
if(m_hToken)
{
::CloseHandle(m_hToken);
m_hToken = NULL;
}
delete m_pRevert;
m_pRevert = NULL;
}
inline bool CAccessToken::EnablePrivilege(LPCTSTR pszPrivilege,
CTokenPrivileges *pPreviousState)
{
CTokenPrivileges NewState;
return NewState.Add(pszPrivilege, true) &&
EnableDisablePrivileges(NewState, pPreviousState);
}
inline bool CAccessToken::EnablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges,
CTokenPrivileges *pPreviousState)
{
return EnableDisablePrivileges(rPrivileges, true, pPreviousState);
}
inline bool CAccessToken::DisablePrivilege(LPCTSTR pszPrivilege,
CTokenPrivileges *pPreviousState)
{
CTokenPrivileges NewState;
return NewState.Add(pszPrivilege, false) &&
EnableDisablePrivileges(NewState, pPreviousState);
}
inline bool CAccessToken::DisablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges,
CTokenPrivileges *pPreviousState)
{
return EnableDisablePrivileges(rPrivileges, false, pPreviousState);
}
inline bool CAccessToken::EnableDisablePrivileges(const CSimpleArray<LPCTSTR> &rPrivileges,
bool bEnable, CTokenPrivileges *pPreviousState)
{
CTokenPrivileges NewState;
for(int i = 0; i < rPrivileges.GetSize(); i++)
if(!NewState.Add(rPrivileges[i], bEnable))
return false;
return EnableDisablePrivileges(NewState, pPreviousState);
}
inline bool CAccessToken::EnableDisablePrivileges(const CTokenPrivileges &rNewState,
CTokenPrivileges *pPreviousState)
{
if(!rNewState.GetCount())
return true;
TOKEN_PRIVILEGES *pNewState = const_cast<TOKEN_PRIVILEGES *>(rNewState.GetPTOKEN_PRIVILEGES());
if(pPreviousState)
{
DWORD dwLength = offsetof(TOKEN_PRIVILEGES, Privileges) +
rNewState.GetCount() * sizeof(LUID_AND_ATTRIBUTES);
TOKEN_PRIVILEGES *pPrevState = static_cast<TOKEN_PRIVILEGES *>(_alloca(dwLength));
if(!::AdjustTokenPrivileges(m_hToken, FALSE, pNewState, dwLength, pPrevState, &dwLength))
return false;
pPreviousState->Add(*pPrevState);
return true;
}
else
return 0 != ::AdjustTokenPrivileges(m_hToken, FALSE, pNewState, 0, NULL, NULL);
}
inline bool CAccessToken::PrivilegeCheck(PPRIVILEGE_SET RequiredPrivileges, bool *pbResult) const
{
BOOL bResult;
if(!::PrivilegeCheck(m_hToken, RequiredPrivileges, &bResult))
return false;
*pbResult = 0 != bResult;
return true;
}
inline bool CAccessToken::GetProcessToken(DWORD dwDesiredAccess, HANDLE hProcess)
{
if(!hProcess)
hProcess = ::GetCurrentProcess();
HANDLE hToken;
if(!::OpenProcessToken(hProcess, dwDesiredAccess, &hToken))
return false;
Clear();
m_hToken = hToken;
return true;
}
inline bool CAccessToken::GetThreadToken(DWORD dwDesiredAccess,
HANDLE hThread, bool bOpenAsSelf)
{
if(!hThread)
hThread = ::GetCurrentThread();
HANDLE hToken;
if(!::OpenThreadToken(hThread, dwDesiredAccess, bOpenAsSelf, &hToken))
return false;
Clear();
m_hToken = hToken;
return true;
}
inline bool CAccessToken::GetEffectiveToken(DWORD dwDesiredAccess)
{
if(!GetThreadToken(dwDesiredAccess))
return GetProcessToken(dwDesiredAccess);
return true;
}
inline void CAccessToken::CheckImpersonation() const
{
#ifdef _DEBUG
// You should not be impersonating at this point. Use GetThreadToken
// instead of the OpenXXXToken functions or call Revert before
// calling Impersonate.
HANDLE hToken;
if(!::OpenThreadToken(::GetCurrentThread(), 0, false, &hToken) &&
::GetLastError() != ERROR_NO_TOKEN)
ATLTRACE(atlTraceSecurity, 2, _T("Caution: replacing thread impersonation token.\n"));
#endif
}
inline bool CAccessToken::OpenThreadToken(DWORD dwDesiredAccess,
bool bImpersonate, bool bOpenAsSelf,
SECURITY_IMPERSONATION_LEVEL sil)
{
CheckImpersonation();
if(!::ImpersonateSelf(sil))
return false;
HANDLE hToken;
if(!::OpenThreadToken(::GetCurrentThread(), dwDesiredAccess, bOpenAsSelf, &hToken))
return false;
Clear();
m_hToken = hToken;
if(!bImpersonate)
::RevertToSelf();
else
{
ATLTRY(m_pRevert = new CRevertToSelf);
if(!m_pRevert)
{
::RevertToSelf();
Clear();
return false;
}
}
return true;
}
#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
inline bool CAccessToken::OpenCOMClientToken(DWORD dwDesiredAccess,
bool bImpersonate, bool bOpenAsSelf)
{
CheckImpersonation();
if(FAILED(::CoImpersonateClient()))
return false;
HANDLE hToken;
if(!::OpenThreadToken(::GetCurrentThread(), dwDesiredAccess, bOpenAsSelf, &hToken))
return false;
Clear();
m_hToken = hToken;
if(!bImpersonate)
::CoRevertToSelf();
else
{
ATLTRY(m_pRevert = new CCoRevertToSelf);
if(!m_pRevert)
{
::CoRevertToSelf();
Clear();
return false;
}
}
return true;
}
#endif //(_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
inline bool CAccessToken::OpenNamedPipeClientToken(HANDLE hPipe, DWORD dwDesiredAccess,
bool bImpersonate, bool bOpenAsSelf)
{
CheckImpersonation();
if(!::ImpersonateNamedPipeClient(hPipe))
return false;
HANDLE hToken;
if(!::OpenThreadToken(::GetCurrentThread(), dwDesiredAccess, bOpenAsSelf, &hToken))
return false;
Clear();
m_hToken = hToken;
if(!bImpersonate)
::RevertToSelf();
else
{
ATLTRY(m_pRevert = new CRevertToSelf);
if(!m_pRevert)
{
::RevertToSelf();
Clear();
return false;
}
}
return true;
}
inline bool CAccessToken::OpenRPCClientToken(RPC_BINDING_HANDLE BindingHandle,
DWORD dwDesiredAccess,
bool bImpersonate, bool bOpenAsSelf)
{
CheckImpersonation();
if(RPC_S_OK != ::RpcImpersonateClient(BindingHandle))
return false;
HANDLE hToken;
if(!::OpenThreadToken(::GetCurrentThread(), dwDesiredAccess, bOpenAsSelf, &hToken))
return false;
Clear();
m_hToken = hToken;
if(!bImpersonate)
::RpcRevertToSelfEx(BindingHandle);
else
{
ATLTRY(m_pRevert = new CRpcRevertToSelfEx(BindingHandle));
if(!m_pRevert)
{
::RpcRevertToSelfEx(BindingHandle);
Clear();
return false;
}
}
return true;
}
inline bool CAccessToken::ImpersonateLoggedOnUser() const
{
CheckImpersonation();
ATLASSERT(m_hToken);
if(m_hToken && ::ImpersonateLoggedOnUser(m_hToken))
{
ATLASSERT(!m_pRevert);
delete m_pRevert;
ATLTRY(m_pRevert = new CRevertToSelf);
if (!m_pRevert)
{
::RevertToSelf();
return false;
}
return true;
}
return false;
}
inline bool CAccessToken::Impersonate(HANDLE hThread) const
{
CheckImpersonation();
ATLASSERT(m_hToken);
if(m_hToken)
return 0 != ::SetThreadToken(hThread ? &hThread : NULL, m_hToken);
return false;
}
inline bool CAccessToken::Revert(HANDLE hThread) const
{
// REVIEW: What if *this* access token isn't the one that's currently doing
// the impersonating?
if(m_pRevert)
{
bool bRet = m_pRevert->Revert();
delete m_pRevert;
m_pRevert = NULL;
return bRet;
}
else
return 0 != ::SetThreadToken(hThread ? &hThread : NULL, NULL);
}
inline bool CAccessToken::LogonUser(LPCTSTR pszUserName,
LPCTSTR pszDomain,
LPCTSTR pszPassword,
DWORD dwLogonType,
DWORD dwLogonProvider)
{
Clear();
return 0 != ::LogonUser(
const_cast<LPTSTR>(pszUserName),
const_cast<LPTSTR>(pszDomain),
const_cast<LPTSTR>(pszPassword),
dwLogonType, dwLogonProvider, &m_hToken);
}
inline bool CAccessToken::LoadUserProfile()
{
ATLASSERT(m_hToken && !m_hProfile);
if(!m_hToken || m_hProfile)
return false;
CSid UserSid;
PROFILEINFO Profile;
if(!GetUser(&UserSid))
return false;
memset(&Profile, 0x00, sizeof(PROFILEINFO));
Profile.dwSize = sizeof(PROFILEINFO);
Profile.lpUserName = const_cast<LPTSTR>(UserSid.AccountName());
if(!::LoadUserProfile(m_hToken, &Profile))
return false;
m_hProfile = Profile.hProfile;
return true;
}
inline bool CAccessToken::SetOwner(const CSid &rSid)
{ TOKEN_OWNER to;
to.Owner = const_cast<SID *>(rSid.GetPSID());
return 0 != ::SetTokenInformation(m_hToken, TokenOwner, &to, sizeof(to));
}
inline bool CAccessToken::SetPrimaryGroup(const CSid &rSid)
{
TOKEN_PRIMARY_GROUP tpg;
tpg.PrimaryGroup = const_cast<SID *>(rSid.GetPSID());
return 0 != ::SetTokenInformation(m_hToken, TokenPrimaryGroup, &tpg, sizeof(tpg));
}
inline bool CAccessToken::SetDefaultDacl(const CDacl &rDacl)
{
TOKEN_DEFAULT_DACL tdd;
tdd.DefaultDacl = const_cast<ACL *>(rDacl.GetPACL());
return 0 != ::SetTokenInformation(m_hToken, TokenDefaultDacl, &tdd, sizeof(tdd));
}
inline bool CAccessToken::CreateImpersonationToken(CAccessToken *pImp,
SECURITY_IMPERSONATION_LEVEL sil) const
{
ATLASSERT(pImp);
if(!pImp)
return false;
HANDLE hToken;
if(!::DuplicateToken(m_hToken, sil, &hToken))
return false;
pImp->Clear();
pImp->m_hToken = hToken;
return true;
}
inline bool CAccessToken::CreatePrimaryToken(CAccessToken *pPri, DWORD dwDesiredAccess,
const CSecurityAttributes *pTokenAttributes) const
{
ATLASSERT(pPri);
if(!pPri)
return false;
HANDLE hToken;
if(!::DuplicateTokenEx(m_hToken, dwDesiredAccess,
const_cast<CSecurityAttributes *>(pTokenAttributes),
SecurityAnonymous, TokenPrimary, &hToken))
{
return false;
}
pPri->Clear();
pPri->m_hToken = hToken;
return true;
}
#if(_WIN32_WINNT >= 0x0500)
// REVIEW should this be something like
/*
inline bool CAccessToken::CreateRestrictedToken(CAccessToken *pRestrictedToken,
const CSidArray &SidsToDisable,
const CLUIDArray &PrivilegesToDelete,
const CSidArray &SidsToRestrict) const*/
inline bool CAccessToken::CreateRestrictedToken(CAccessToken *pRestrictedToken,
const CTokenGroups &SidsToDisable,
const CTokenGroups &SidsToRestrict,
const CTokenPrivileges &PrivilegesToDelete) const
{
ATLASSERT(pRestrictedToken);
if(!pRestrictedToken)
return false;
HANDLE hToken;
SID_AND_ATTRIBUTES *pSidsToDisable;
SID_AND_ATTRIBUTES *pSidsToRestrict;
LUID_AND_ATTRIBUTES *pPrivilegesToDelete;
DWORD dwDisableSidCount;
DWORD dwDeletePrivilegesCount;
DWORD dwRestrictedSidCount;
if(dwDisableSidCount = SidsToDisable.GetCount())
{
const TOKEN_GROUPS * pTOKEN_GROUPS = SidsToDisable.GetPTOKEN_GROUPS();
ATLASSERT(pTOKEN_GROUPS != NULL);
if(pTOKEN_GROUPS != NULL)
{
pSidsToDisable = const_cast<SID_AND_ATTRIBUTES *>
(pTOKEN_GROUPS->Groups);
}
else
{
return false;
}
}
else
{
pSidsToDisable = NULL;
}
if(dwRestrictedSidCount = SidsToRestrict.GetCount())
{
const TOKEN_GROUPS * pTOKEN_GROUPS = SidsToRestrict.GetPTOKEN_GROUPS();
ATLASSERT(pTOKEN_GROUPS != NULL);
if(pTOKEN_GROUPS != NULL)
{
pSidsToRestrict = const_cast<SID_AND_ATTRIBUTES *>
(pTOKEN_GROUPS->Groups);
}
else
{
return false;
}
}
else
{
pSidsToRestrict = NULL;
}
if(dwDeletePrivilegesCount = PrivilegesToDelete.GetCount())
{
const TOKEN_PRIVILEGES * pTOKEN_PRIVILEGES = PrivilegesToDelete.GetPTOKEN_PRIVILEGES();
ATLASSERT(pTOKEN_PRIVILEGES != NULL);
if(pTOKEN_PRIVILEGES != NULL)
{
pPrivilegesToDelete = const_cast<LUID_AND_ATTRIBUTES *>
(pTOKEN_PRIVILEGES->Privileges);
}
else
{
return false;
}
}
else
{
pPrivilegesToDelete = NULL;
}
if(!::CreateRestrictedToken(m_hToken, 0,
dwDisableSidCount, pSidsToDisable,
dwDeletePrivilegesCount, pPrivilegesToDelete,
dwRestrictedSidCount, pSidsToRestrict, &hToken))
{
return false;
}
pRestrictedToken->Clear();
pRestrictedToken->m_hToken = hToken;
return true;
}
#endif // _WIN32_WINNT >= 0x0500
inline bool CAccessToken::GetLogonSid(CSid *pSid) const
{
ATLASSERT(pSid);
if(!pSid)
return false;
DWORD dwLen;
::GetTokenInformation(m_hToken, TokenGroups, NULL, 0, &dwLen);
if(::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return false;
TOKEN_GROUPS *pGroups = static_cast<TOKEN_GROUPS *>(_alloca(dwLen));
if(::GetTokenInformation(m_hToken, TokenGroups, pGroups, dwLen, &dwLen))
for(UINT i = 0; i < pGroups->GroupCount; i++)
if(pGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID)
{
*pSid = *static_cast<SID *>(pGroups->Groups[i].Sid);
return true;
}
return false;
}
inline bool CAccessToken::GetTokenId(LUID *pluid) const
{
ATLASSERT(pluid);
if(!pluid)
return false;
TOKEN_STATISTICS Statistics;
if(!GetStatistics(&Statistics))
return false;
*pluid = Statistics.TokenId;
return true;
}
inline bool CAccessToken::GetLogonSessionId(LUID *pluid) const
{
ATLASSERT(pluid);
if(!pluid)
return false;
TOKEN_STATISTICS Statistics;
if(!GetStatistics(&Statistics))
return false;
*pluid = Statistics.AuthenticationId;
return true;
}
inline bool CAccessToken::CheckTokenMembership(const CSid &rSid, bool *pbIsMember) const
{
// "this" must be an impersonation token and NOT a primary token
BOOL bIsMember;
ATLASSERT(pbIsMember);
if (!pbIsMember)
return false;
#if(_WIN32_WINNT >= 0x0500)
if(::CheckTokenMembership(m_hToken, const_cast<SID *>(rSid.GetPSID()), &bIsMember))
#else
GENERIC_MAPPING gm = {0, 0, 0, 1};
PRIVILEGE_SET ps;
DWORD cb = sizeof(PRIVILEGE_SET);
DWORD ga;
CSecurityDesc sd;
CDacl dacl;
if (!dacl.AddAllowedAce(rSid, 1))
return false;
sd.SetOwner(rSid);
sd.SetGroup(rSid);
sd.SetDacl(dacl);
if(::AccessCheck(const_cast<SECURITY_DESCRIPTOR *>(sd.GetPSECURITY_DESCRIPTOR()),
m_hToken, 1, &gm, &ps, &cb, &ga, &bIsMember))
#endif
{
*pbIsMember = 0 != bIsMember;
return true;
}
return false;
}
inline bool CAccessToken::CreateProcessAsUser(
LPCTSTR pApplicationName, LPTSTR pCommandLine,
LPPROCESS_INFORMATION pProcessInformation,
LPSTARTUPINFO pStartupInfo,
DWORD dwCreationFlags,
bool bLoadProfile,
const CSecurityAttributes *pProcessAttributes,
const CSecurityAttributes *pThreadAttributes,
bool bInherit,
LPCTSTR pCurrentDirectory)
{
LPVOID pEnvironmentBlock;
PROFILEINFO Profile;
CSid UserSid;
HANDLE hToken = m_hToken;
// Straighten out impersonation problems...
TOKEN_TYPE TokenType;
if(!GetType(&TokenType) &&
TokenType != TokenPrimary &&
!::DuplicateTokenEx(m_hToken, TOKEN_ALL_ACCESS, NULL,
SecurityAnonymous, TokenPrimary, &hToken))
{
return false;
}
// Profile
if(bLoadProfile && !m_hProfile)
{
if(!GetUser(&UserSid))
{
if(TokenType != TokenPrimary)
::CloseHandle(hToken);
return false;
}
memset(&Profile, 0x00, sizeof(PROFILEINFO));
Profile.dwSize = sizeof(PROFILEINFO);
Profile.lpUserName = const_cast<LPTSTR>(UserSid.AccountName());
if(::LoadUserProfile(hToken, &Profile))
m_hProfile = Profile.hProfile;
}
// Environment block
if(!::CreateEnvironmentBlock(&pEnvironmentBlock, hToken, bInherit))
return false;
BOOL bRetVal = ::CreateProcessAsUser(
hToken,
pApplicationName,
pCommandLine,
const_cast<CSecurityAttributes *>(pProcessAttributes),
const_cast<CSecurityAttributes *>(pThreadAttributes),
bInherit,
dwCreationFlags,
pEnvironmentBlock,
pCurrentDirectory,
pStartupInfo,
pProcessInformation);
if(TokenType != TokenPrimary)
::CloseHandle(hToken);
::DestroyEnvironmentBlock(pEnvironmentBlock);
return bRetVal != 0;
}
//*******************************************
// Private Security
class CPrivateObjectSecurityDesc : public CSecurityDesc
{
public:
CPrivateObjectSecurityDesc() : m_bPrivate(false), CSecurityDesc(){}
~CPrivateObjectSecurityDesc() {Clear();}
bool Create(const CSecurityDesc *pParent, const CSecurityDesc *pCreator,
bool bIsDirectoryObject, const CAccessToken &Token, PGENERIC_MAPPING GenericMapping);
#if(_WIN32_WINNT >= 0x0500)
bool Create(const CSecurityDesc *pParent, const CSecurityDesc *pCreator,
GUID *ObjectType, bool bIsContainerObject, ULONG AutoInheritFlags,
const CAccessToken &Token, PGENERIC_MAPPING GenericMapping);
#endif
bool Get(SECURITY_INFORMATION si, CSecurityDesc *pResult) const;
bool Set(SECURITY_INFORMATION si, const CSecurityDesc &Modification,
PGENERIC_MAPPING GenericMapping, const CAccessToken &Token);
#if(_WIN32_WINNT >= 0x0500)
bool Set(SECURITY_INFORMATION si, const CSecurityDesc &Modification,
ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping,
const CAccessToken &Token);
bool ConvertToAutoInherit(const CSecurityDesc *pParent, GUID *ObjectType,
bool bIsDirectoryObject, PGENERIC_MAPPING GenericMapping);
#endif
protected:
void Clear();
private:
bool m_bPrivate;
CPrivateObjectSecurityDesc(const CPrivateObjectSecurityDesc &rhs);
CPrivateObjectSecurityDesc &operator=(const CPrivateObjectSecurityDesc &rhs);
};
inline void CPrivateObjectSecurityDesc::Clear()
{
if(m_bPrivate)
{
ATLVERIFY(::DestroyPrivateObjectSecurity(reinterpret_cast<PSECURITY_DESCRIPTOR *>(&m_pSecurityDescriptor)));
m_bPrivate = false;
m_pSecurityDescriptor = NULL;
}
else
CSecurityDesc::Clear();
}
inline bool CPrivateObjectSecurityDesc::Create(const CSecurityDesc *pParent, const CSecurityDesc *pCreator,
bool bIsDirectoryObject, const CAccessToken &Token,
PGENERIC_MAPPING GenericMapping)
{
Clear();
const SECURITY_DESCRIPTOR *pSDParent = pParent ? pParent->GetPSECURITY_DESCRIPTOR() : NULL;
const SECURITY_DESCRIPTOR *pSDCreator = pCreator ? pCreator->GetPSECURITY_DESCRIPTOR() : NULL;
if(!::CreatePrivateObjectSecurity(
const_cast<SECURITY_DESCRIPTOR *>(pSDParent),
const_cast<SECURITY_DESCRIPTOR *>(pSDCreator),
reinterpret_cast<PSECURITY_DESCRIPTOR *>(&m_pSecurityDescriptor),
bIsDirectoryObject, Token.GetHandle(), GenericMapping))
{
return false;
}
m_bPrivate = true;
return true;
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CPrivateObjectSecurityDesc::Create(const CSecurityDesc *pParent, const CSecurityDesc *pCreator,
GUID *ObjectType, bool bIsContainerObject, ULONG AutoInheritFlags,
const CAccessToken &Token, PGENERIC_MAPPING GenericMapping)
{
Clear();
const SECURITY_DESCRIPTOR *pSDParent = pParent ? pParent->GetPSECURITY_DESCRIPTOR() : NULL;
const SECURITY_DESCRIPTOR *pSDCreator = pCreator ? pCreator->GetPSECURITY_DESCRIPTOR() : NULL;
if(!::CreatePrivateObjectSecurityEx(
const_cast<SECURITY_DESCRIPTOR *>(pSDParent),
const_cast<SECURITY_DESCRIPTOR *>(pSDCreator),
reinterpret_cast<PSECURITY_DESCRIPTOR *>(&m_pSecurityDescriptor),
ObjectType, bIsContainerObject, AutoInheritFlags, Token.GetHandle(), GenericMapping))
{
return false;
}
m_bPrivate = true;
return true;
}
#endif
inline bool CPrivateObjectSecurityDesc::Get(SECURITY_INFORMATION si, CSecurityDesc *pResult) const
{
ATLASSERT(pResult);
if(!pResult)
return false;
if(!m_bPrivate)
return false;
DWORD dwLength = 0;
SECURITY_DESCRIPTOR *pSDResult = NULL;
if(!::GetPrivateObjectSecurity(m_pSecurityDescriptor, si, pSDResult, dwLength, &dwLength) &&
::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
return false;
}
pSDResult = (SECURITY_DESCRIPTOR *) _alloca(dwLength);
if(!::GetPrivateObjectSecurity(m_pSecurityDescriptor, si, pSDResult, dwLength, &dwLength))
return false;
*pResult = *pSDResult;
return true;
}
inline bool CPrivateObjectSecurityDesc::Set(SECURITY_INFORMATION si, const CSecurityDesc &Modification,
PGENERIC_MAPPING GenericMapping, const CAccessToken &Token)
{
if(!m_bPrivate)
return false;
const SECURITY_DESCRIPTOR *pSDModification = Modification.GetPSECURITY_DESCRIPTOR();
return 0 != ::SetPrivateObjectSecurity(si,
const_cast<SECURITY_DESCRIPTOR *>(pSDModification),
reinterpret_cast<PSECURITY_DESCRIPTOR *>(&m_pSecurityDescriptor),
GenericMapping, Token.GetHandle());
}
#if(_WIN32_WINNT >= 0x0500)
inline bool CPrivateObjectSecurityDesc::Set(SECURITY_INFORMATION si, const CSecurityDesc &Modification,
ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping,
const CAccessToken &Token)
{
if(!m_bPrivate)
return false;
const SECURITY_DESCRIPTOR *pSDModification = Modification.GetPSECURITY_DESCRIPTOR();
return 0 != ::SetPrivateObjectSecurityEx(si,
const_cast<SECURITY_DESCRIPTOR *>(pSDModification),
reinterpret_cast<PSECURITY_DESCRIPTOR *>(&m_pSecurityDescriptor),
AutoInheritFlags, GenericMapping, Token.GetHandle());
}
inline bool CPrivateObjectSecurityDesc::ConvertToAutoInherit(const CSecurityDesc *pParent, GUID *ObjectType,
bool bIsDirectoryObject, PGENERIC_MAPPING GenericMapping)
{
if(!m_bPrivate)
return false;
const SECURITY_DESCRIPTOR *pSDParent = pParent ? pParent->GetPSECURITY_DESCRIPTOR() : NULL;
SECURITY_DESCRIPTOR *pSD;
if(!::ConvertToAutoInheritPrivateObjectSecurity(
const_cast<SECURITY_DESCRIPTOR *>(pSDParent),
m_pSecurityDescriptor,
reinterpret_cast<PSECURITY_DESCRIPTOR *>(&pSD),
ObjectType, bIsDirectoryObject, GenericMapping))
{
return false;
}
Clear();
m_bPrivate = true;
m_pSecurityDescriptor = pSD;
return true;
}
#endif // _WIN32_WINNT >= 0x500
//*******************************************
// Globals
inline bool AtlGetSecurityDescriptor(LPCTSTR pszObjectName,
SE_OBJECT_TYPE ObjectType,
CSecurityDesc *pSecurityDescriptor)
{
ATLASSERT(pSecurityDescriptor);
if(!pSecurityDescriptor)
return false;
SECURITY_DESCRIPTOR *pSD;
SECURITY_INFORMATION si =
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION;
DWORD dwErr;
CAccessToken at;
CTokenPrivileges TokenPrivileges;
// Try SACL
if(at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) &&
at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges))
{
si |= SACL_SECURITY_INFORMATION;
}
// REVIEW: should *we* impersonate, or should we let the user impersonate?
if(!at.Impersonate())
return false;
dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType, si,
NULL, NULL, NULL, NULL, (PSECURITY_DESCRIPTOR *) &pSD);
at.EnableDisablePrivileges(TokenPrivileges);
if(dwErr != ERROR_SUCCESS && (si & SACL_SECURITY_INFORMATION))
{
// could be the SACL causing problems... try without
si &= ~SACL_SECURITY_INFORMATION;
dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType, si,
NULL, NULL, NULL, NULL, (PSECURITY_DESCRIPTOR *) &pSD);
}
at.Revert();
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSecurityDescriptor = *pSD;
::LocalFree(pSD);
return true;
}
inline bool AtlGetSecurityDescriptor(HANDLE hObject,
SE_OBJECT_TYPE ObjectType,
CSecurityDesc *pSecurityDescriptor)
{
ATLASSERT(pSecurityDescriptor);
if(!pSecurityDescriptor)
return false;
SECURITY_DESCRIPTOR *pSD;
SECURITY_INFORMATION si =
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION;
DWORD dwErr;
CAccessToken at;
CTokenPrivileges TokenPrivileges;
// Try SACL
if(at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) &&
at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges))
{
si |= SACL_SECURITY_INFORMATION;
}
// REVIEW: should *we* impersonate, or should we let the user impersonate?
if(!at.Impersonate())
return false;
dwErr = ::GetSecurityInfo(hObject, ObjectType, si,
NULL, NULL, NULL, NULL, reinterpret_cast<PSECURITY_DESCRIPTOR *>(&pSD));
at.EnableDisablePrivileges(TokenPrivileges);
if(dwErr != ERROR_SUCCESS && (si & SACL_SECURITY_INFORMATION))
{
// could be the SACL causing problems... try without
si &= ~SACL_SECURITY_INFORMATION;
dwErr = ::GetSecurityInfo(hObject, ObjectType, si,
NULL, NULL, NULL, NULL, reinterpret_cast<PSECURITY_DESCRIPTOR *>(&pSD));
}
at.Revert();
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSecurityDescriptor = *pSD;
::LocalFree(pSD);
return true;
}
inline bool AtlGetOwnerSid(HANDLE hObject, SE_OBJECT_TYPE ObjectType, CSid *pSid)
{
ATLASSERT(hObject && pSid);
if(!hObject || !pSid)
return false;
SID *pOwner;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetSecurityInfo(hObject, ObjectType, OWNER_SECURITY_INFORMATION,
(PSID *) &pOwner, NULL, NULL, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSid = *pOwner;
::LocalFree(pSD);
return true;
}
inline bool AtlSetOwnerSid(HANDLE hObject, SE_OBJECT_TYPE ObjectType, const CSid &rSid)
{
ATLASSERT(hObject && rSid.IsValid());
if(!hObject || !rSid.IsValid())
return false;
DWORD dwErr = ::SetSecurityInfo(hObject, ObjectType, OWNER_SECURITY_INFORMATION,
const_cast<SID *>(rSid.GetPSID()), NULL, NULL, NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetOwnerSid(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, CSid *pSid)
{
ATLASSERT(pszObjectName && pSid);
if(!pszObjectName || !pSid)
return false;
SID *pOwner;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
OWNER_SECURITY_INFORMATION, reinterpret_cast<PSID *>(&pOwner), NULL, NULL, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSid = *pOwner;
::LocalFree(pSD);
return true;
}
inline bool AtlSetOwnerSid(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, const CSid &rSid)
{
ATLASSERT(pszObjectName && rSid.IsValid());
if(!pszObjectName || !rSid.IsValid())
return false;
DWORD dwErr = ::SetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
OWNER_SECURITY_INFORMATION, const_cast<SID *>(rSid.GetPSID()), NULL, NULL, NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetGroupSid(HANDLE hObject, SE_OBJECT_TYPE ObjectType, CSid *pSid)
{
ATLASSERT(hObject && pSid);
if(!hObject || !pSid)
return false;
SID *pGroup;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetSecurityInfo(hObject, ObjectType, GROUP_SECURITY_INFORMATION,
NULL, reinterpret_cast<PSID *>(&pGroup), NULL, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSid = *pGroup;
::LocalFree(pSD);
return true;
}
inline bool AtlSetGroupSid(HANDLE hObject, SE_OBJECT_TYPE ObjectType, const CSid &rSid)
{
ATLASSERT(hObject && rSid.IsValid());
if(!hObject || !rSid.IsValid())
return false;
DWORD dwErr = ::SetSecurityInfo(hObject, ObjectType, GROUP_SECURITY_INFORMATION,
NULL, const_cast<SID *>(rSid.GetPSID()), NULL, NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetGroupSid(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, CSid *pSid)
{
ATLASSERT(pszObjectName && pSid);
if(!pszObjectName || !pSid)
return false;
SID *pGroup;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName),
ObjectType, GROUP_SECURITY_INFORMATION, NULL,
reinterpret_cast<PSID *>(&pGroup), NULL, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
*pSid = *pGroup;
::LocalFree(pSD);
return true;
}
inline bool AtlSetGroupSid(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, const CSid &rSid)
{
ATLASSERT(pszObjectName && rSid.IsValid());
if(!pszObjectName || !rSid.IsValid())
return false;
DWORD dwErr = ::SetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
GROUP_SECURITY_INFORMATION, NULL, const_cast<SID *>(rSid.GetPSID()), NULL, NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetDacl(HANDLE hObject, SE_OBJECT_TYPE ObjectType, CDacl *pDacl)
{
ATLASSERT(hObject && pDacl);
if(!hObject || !pDacl)
return false;
ACL *pAcl;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetSecurityInfo(hObject, ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, &pAcl, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
if(pAcl)
*pDacl = *pAcl;
::LocalFree(pSD);
return NULL != pAcl;
}
inline bool AtlSetDacl(HANDLE hObject, SE_OBJECT_TYPE ObjectType, const CDacl &rDacl,
DWORD dwInheritanceFlowControl = 0)
{
ATLASSERT(hObject);
if(!hObject)
return false;
ATLASSERT(
dwInheritanceFlowControl == 0 ||
dwInheritanceFlowControl == PROTECTED_DACL_SECURITY_INFORMATION ||
dwInheritanceFlowControl == UNPROTECTED_DACL_SECURITY_INFORMATION);
DWORD dwErr = ::SetSecurityInfo(hObject, ObjectType,
DACL_SECURITY_INFORMATION | dwInheritanceFlowControl,
NULL, NULL, const_cast<ACL *>(rDacl.GetPACL()), NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetDacl(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, CDacl *pDacl)
{
ATLASSERT(pszObjectName && pDacl);
if(!pszObjectName || !pDacl)
return false;
ACL *pAcl;
PSECURITY_DESCRIPTOR pSD;
DWORD dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
DACL_SECURITY_INFORMATION, NULL, NULL, &pAcl, NULL, &pSD);
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
if(pAcl)
*pDacl = *pAcl;
::LocalFree(pSD);
return NULL != pAcl;
}
inline bool AtlSetDacl(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, const CDacl &rDacl,
DWORD dwInheritanceFlowControl = 0)
{
ATLASSERT(pszObjectName);
if(!pszObjectName)
return false;
ATLASSERT(
dwInheritanceFlowControl == 0 ||
dwInheritanceFlowControl == PROTECTED_DACL_SECURITY_INFORMATION ||
dwInheritanceFlowControl == UNPROTECTED_DACL_SECURITY_INFORMATION);
DWORD dwErr = ::SetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
DACL_SECURITY_INFORMATION | dwInheritanceFlowControl,
NULL, NULL, const_cast<ACL *>(rDacl.GetPACL()), NULL);
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetSacl(HANDLE hObject, SE_OBJECT_TYPE ObjectType, CSacl *pSacl)
{
ATLASSERT(hObject && pSacl);
if(!hObject || !pSacl)
return false;
ACL *pAcl;
PSECURITY_DESCRIPTOR pSD;
CAccessToken at;
CTokenPrivileges TokenPrivileges;
// REVIEW: A LOT. I'm wondering whether or not it's absolutely necessary to impersonate
// the thread token here (rather than let the user do it or something).
// Furthermore, should SecurityImpersonation be hard-coded? Maybe it should be a param?
if(!at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) ||
!at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges) ||
!at.Impersonate())
{
return false;
}
DWORD dwErr = ::GetSecurityInfo(hObject, ObjectType, SACL_SECURITY_INFORMATION,
NULL, NULL, NULL, &pAcl, &pSD);
at.EnableDisablePrivileges(TokenPrivileges);
at.Revert();
if(dwErr != ERROR_SUCCESS)
{
::SetLastError(dwErr);
return false;
}
if(pAcl)
*pSacl = *pAcl;
::LocalFree(pSD);
return NULL != pAcl;
}
inline bool AtlSetSacl(HANDLE hObject, SE_OBJECT_TYPE ObjectType, const CSacl &rSacl,
DWORD dwInheritanceFlowControl = 0)
{
ATLASSERT(hObject);
CAccessToken at;
CTokenPrivileges TokenPrivileges;
ATLASSERT(
dwInheritanceFlowControl == 0 ||
dwInheritanceFlowControl == PROTECTED_SACL_SECURITY_INFORMATION ||
dwInheritanceFlowControl == UNPROTECTED_SACL_SECURITY_INFORMATION);
// REVIEW: Should we be impersonating?
if(!hObject ||
!at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) ||
!at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges) ||
!at.Impersonate())
{
return false;
}
DWORD dwErr = ::SetSecurityInfo(hObject, ObjectType,
SACL_SECURITY_INFORMATION | dwInheritanceFlowControl,
NULL, NULL, NULL, const_cast<ACL *>(rSacl.GetPACL()));
at.EnableDisablePrivileges(TokenPrivileges);
at.Revert();
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
inline bool AtlGetSacl(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, CSacl *pSacl)
{
ATLASSERT(pszObjectName && pSacl);
if(!pszObjectName || !pSacl)
return false;
ACL *pAcl;
PSECURITY_DESCRIPTOR pSD;
CAccessToken at;
CTokenPrivileges TokenPrivileges;
// REVIEW: Should we be impersonating?
if(!at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) ||
!at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges) ||
!at.Impersonate())
{
return false;
}
DWORD dwErr = ::GetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
SACL_SECURITY_INFORMATION, NULL, NULL, NULL, &pAcl, &pSD);
at.EnableDisablePrivileges(TokenPrivileges);
at.Revert();
::SetLastError(dwErr);
if(dwErr != ERROR_SUCCESS)
return false;
if(pAcl)
*pSacl = *pAcl;
::LocalFree(pSD);
return NULL != pAcl;
}
inline bool AtlSetSacl(LPCTSTR pszObjectName, SE_OBJECT_TYPE ObjectType, const CSacl &rSacl,
DWORD dwInheritanceFlowControl = 0)
{
ATLASSERT(pszObjectName);
CAccessToken at;
CTokenPrivileges TokenPrivileges;
ATLASSERT(
dwInheritanceFlowControl == 0 ||
dwInheritanceFlowControl == PROTECTED_SACL_SECURITY_INFORMATION ||
dwInheritanceFlowControl == UNPROTECTED_SACL_SECURITY_INFORMATION);
// REVIEW: Should we be impersonating or should the user take care of this?
if(!pszObjectName ||
!at.OpenThreadToken(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
false, false, SecurityImpersonation) ||
!at.EnablePrivilege(SE_SECURITY_NAME, &TokenPrivileges) ||
!at.Impersonate())
{
return false;
}
DWORD dwErr = ::SetNamedSecurityInfo(const_cast<LPTSTR>(pszObjectName), ObjectType,
SACL_SECURITY_INFORMATION | dwInheritanceFlowControl,
NULL, NULL, NULL, const_cast<ACL *>(rSacl.GetPACL()));
at.EnableDisablePrivileges(TokenPrivileges);
at.Revert();
::SetLastError(dwErr);
return ERROR_SUCCESS == dwErr;
}
} // namespace ATL
#endif // __ATLSECURITY_H__