// 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 #include #include #include #include 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 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(&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(&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(_alloca(::GetSidLengthRequired(nSubAuthorityCount))); if(!::InitializeSid(pSid, const_cast(&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(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(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(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(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(&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 CAccessMaskArray; typedef CSimpleArray CAceTypeArray; typedef CSimpleArray 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(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(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 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(&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(&pHeader))) AtlThrowLastWin32(); AccessMask = *reinterpret_cast (reinterpret_cast(pHeader) + sizeof(ACE_HEADER)); switch(pHeader->AceType) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: Sid = *reinterpret_cast (reinterpret_cast(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 (pHeader) + offsetof(ACCESS_ALLOWED_OBJECT_ACE, SidStart); DWORD dwFlags = reinterpret_cast(pHeader)->Flags; if(dwFlags & ACE_OBJECT_TYPE_PRESENT) { pObjectType = reinterpret_cast (reinterpret_cast(pHeader) + offsetof(ACCESS_ALLOWED_OBJECT_ACE, ObjectType)); } else pb -= sizeof(GUID); if(dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { pInheritedObjectType = reinterpret_cast (reinterpret_cast(pHeader) + (pObjectType ? offsetof(ACCESS_ALLOWED_OBJECT_ACE, InheritedObjectType) : offsetof(ACCESS_ALLOWED_OBJECT_ACE, ObjectType))); } else pb -= sizeof(GUID); Sid = *reinterpret_cast(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(malloc(nLength)); if(!pAce) return NULL; memset(pAce, 0x00, nLength); pAce->Header.AceSize = static_cast(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(malloc(nLength)); if(!pAce) return NULL; memset(pAce, 0x00, nLength); pAce->Header.AceSize = static_cast(nLength); pAce->Header.AceFlags = m_AceFlags; pAce->Header.AceType = AceType(); pAce->Mask = m_dwAccessMask; pAce->Flags = 0; BYTE *pb = (reinterpret_cast(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(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 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(&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(&pHeader))) AtlThrowLastWin32(); AccessMask = *reinterpret_cast (reinterpret_cast(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 (reinterpret_cast(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 (pHeader) + offsetof(SYSTEM_AUDIT_OBJECT_ACE, SidStart); DWORD dwFlags = reinterpret_cast(pHeader)->Flags; if(dwFlags & ACE_OBJECT_TYPE_PRESENT) { pObjectType = reinterpret_cast (reinterpret_cast(pHeader) + offsetof(SYSTEM_AUDIT_OBJECT_ACE, ObjectType)); } else pb -= sizeof(GUID); if(dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { pInheritedObjectType = reinterpret_cast (reinterpret_cast(pHeader) + (pObjectType ? offsetof(SYSTEM_AUDIT_OBJECT_ACE, InheritedObjectType) : offsetof(SYSTEM_AUDIT_OBJECT_ACE, ObjectType))); } else pb -= sizeof(GUID); Sid = *reinterpret_cast(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(malloc(nLength)); if(!pAce) return NULL; memset(pAce, 0x00, nLength); pAce->Header.AceSize = static_cast(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(malloc(nLength)); if(!pAce) return NULL; memset(pAce, 0x00, nLength); pAce->Header.AceType = SYSTEM_AUDIT_OBJECT_ACE_TYPE; pAce->Header.AceSize = static_cast(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(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 (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(&rhs); DWORD dwRev, dwLen = ::GetSecurityDescriptorLength(pSD); m_pSecurityDescriptor = static_cast(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(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(malloc(dwSD)); pOwner = static_cast(dwOwner ? malloc(dwOwner) : NULL); pGroup = static_cast(dwGroup ? malloc(dwGroup) : NULL); pDacl = static_cast(dwDacl ? malloc(dwDacl) : NULL); pSacl = static_cast(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(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.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.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(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(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 { 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::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 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 CNames; typedef CSimpleArray 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 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(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(&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(&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 *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 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(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(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(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 *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 &rPrivileges, CTokenPrivileges *pPreviousState = NULL); bool DisablePrivilege(LPCTSTR pszPrivilege, CTokenPrivileges *pPreviousState = NULL); bool DisablePrivileges(const CSimpleArray &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 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(rWork.Owner);} template<> void InfoTypeToRetType(CSid *pRet, const TOKEN_PRIMARY_GROUP &rWork) const {ATLASSERT(pRet); *pRet = *static_cast(rWork.PrimaryGroup);} template<> void InfoTypeToRetType(CSid *pRet, const TOKEN_USER &rWork) const {ATLASSERT(pRet); *pRet = *static_cast(rWork.User.Sid);} template 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(_alloca(dwLen)); if(!::GetTokenInformation(m_hToken, TokenClass, pWork, dwLen, &dwLen)) return false; InfoTypeToRetType(pRet, *pWork); return true; } template 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(pDacl, TokenDefaultDacl);} bool GetGroups(CTokenGroups *pGroups) const {return GetInfoConvert(pGroups, TokenGroups);} bool GetImpersonationLevel(SECURITY_IMPERSONATION_LEVEL *pImpersonationLevel) const {return GetInfo(pImpersonationLevel, TokenImpersonationLevel);} bool GetOwner(CSid *pSid) const {return GetInfoConvert(pSid, TokenOwner);} bool GetPrimaryGroup(CSid *pSid) const {return GetInfoConvert(pSid, TokenPrimaryGroup);} bool GetPrivileges(CTokenPrivileges *pPrivileges) const {return GetInfoConvert(pPrivileges, TokenPrivileges);} bool GetTerminalServicesSessionId(DWORD *pdwSessionId) const {return GetInfo(pdwSessionId, TokenSessionId);} bool GetSource(TOKEN_SOURCE *pSource) const {return GetInfo(pSource, TokenSource);} bool GetStatistics(TOKEN_STATISTICS *pStatistics) const {return GetInfo(pStatistics, TokenStatistics);} bool GetType(TOKEN_TYPE *pType) const {return GetInfo(pType, TokenType);} bool GetUser(CSid *pSid) const {return GetInfoConvert(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 &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 &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 &rPrivileges, CTokenPrivileges *pPreviousState) { return EnableDisablePrivileges(rPrivileges, false, pPreviousState); } inline bool CAccessToken::EnableDisablePrivileges(const CSimpleArray &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(rNewState.GetPTOKEN_PRIVILEGES()); if(pPreviousState) { DWORD dwLength = offsetof(TOKEN_PRIVILEGES, Privileges) + rNewState.GetCount() * sizeof(LUID_AND_ATTRIBUTES); TOKEN_PRIVILEGES *pPrevState = static_cast(_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(pszUserName), const_cast(pszDomain), const_cast(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(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(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(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(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(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 (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 (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 (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(_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(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(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(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(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(pProcessAttributes), const_cast(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(&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(pSDParent), const_cast(pSDCreator), reinterpret_cast(&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(pSDParent), const_cast(pSDCreator), reinterpret_cast(&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(pSDModification), reinterpret_cast(&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(pSDModification), reinterpret_cast(&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(pSDParent), m_pSecurityDescriptor, reinterpret_cast(&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(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(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(&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(&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(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(pszObjectName), ObjectType, OWNER_SECURITY_INFORMATION, reinterpret_cast(&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(pszObjectName), ObjectType, OWNER_SECURITY_INFORMATION, const_cast(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(&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(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(pszObjectName), ObjectType, GROUP_SECURITY_INFORMATION, NULL, reinterpret_cast(&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(pszObjectName), ObjectType, GROUP_SECURITY_INFORMATION, NULL, const_cast(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(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(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(pszObjectName), ObjectType, DACL_SECURITY_INFORMATION | dwInheritanceFlowControl, NULL, NULL, const_cast(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(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(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(pszObjectName), ObjectType, SACL_SECURITY_INFORMATION | dwInheritanceFlowControl, NULL, NULL, NULL, const_cast(rSacl.GetPACL())); at.EnableDisablePrivileges(TokenPrivileges); at.Revert(); ::SetLastError(dwErr); return ERROR_SUCCESS == dwErr; } } // namespace ATL #endif // __ATLSECURITY_H__