4682 lines
112 KiB
C++
4682 lines
112 KiB
C++
// 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__
|