#include "stdafx.h"
static GENERIC_MAPPING g_GenericMapping = {
ATL::SecureClass::ReadLen,
ATL::SecureClass::WriteLen | ATL::SecureClass::CopyClass,
ATL::SecureClass::SetClassSecurity,
ATL::SecureClass::ReadLen | ATL::SecureClass::WriteLen | ATL::SecureClass::CopyClass |
ATL::SecureClass::SetClassSecurity
};
SecureClass::SecureClass(int FullRights, const CHandle &ThreadHandle) : len(4.)
{
{/* Get an impersonation token from the thread handle */
CAccessToken ImpersonationToken;
if(!ImpersonationToken.GetThreadToken(TOKEN_QUERY | TOKEN_DUPLICATE, ThreadHandle, true))
{
ImpersonationToken.GetEffectiveToken(TOKEN_QUERY | TOKEN_DUPLICATE);
}
ImpersonationToken.CreateImpersonationToken(&this->ProcToken);
}
/** CSecurityDesc creates a copy of the security descriptor rather than attach a security descriptor.
* This means DestroyPrivateObjectSecurity() will not work.
**/
if(::CreatePrivateObjectSecurity(NULL, /* This security descriptor has no parent */
NULL, /* The defualt constructor must start from scratch */
&this->ppSD,
FALSE, /* Containers aren't supported in this class */
ProcToken.GetHandle(), /* Impersonation token. */
&g_GenericMapping) != TRUE) /* GenericMapping */
{
throw ATL::CAtlException(HRESULT_FROM_WIN32(::GetLastError()));
}
{/* We need to create a default DACL based on the access right desired. */
std::basic_stringstream<TCHAR> osTmp;
CSid UserSid;
{
CStringT<TCHAR, StrTraitATL<TCHAR> > UserName;
DWORD UserNameLength = 0;
GetUserName(NULL, &UserNameLength);
GetUserName(UserName.GetBuffer(UserNameLength), &UserNameLength);
UserName.ReleaseBuffer();
UserSid.LoadAccount(UserName);
}
osTmp << _T("D:(A;;") << std::hex << _T("0x") << FullRights << std::dec << _T(";;;") <<
UserSid.Sid() << _T(")(A;;GA;;;SY)") << std::ends;
CSecurityDesc pNewSD;
pNewSD.FromString(osTmp.str().c_str());
::SetPrivateObjectSecurity(DACL_SECURITY_INFORMATION, const_cast<SECURITY_DESCRIPTOR *>
(pNewSD.GetPSECURITY_DESCRIPTOR()), &this->ppSD, &g_GenericMapping, &ProcToken);
}
}
SecureClass::SecureClass(const SecureClass &OldClass)
: len(OldClass.len)
{/* This is a special copy constructor. */
if(!OldClass.CheckClassAccess(CopyClass))
{
throw ATL::CAtlException(0x80070005);
}
HANDLE newToken = this->ProcToken.GetHandle();
if(::DuplicateHandle(::GetCurrentProcess(), OldClass.ProcToken.GetHandle(), ::GetCurrentProcess(),
&newToken, 0, FALSE, DUPLICATE_SAME_ACCESS) != TRUE)
{
throw ATL::CAtlException(HRESULT_FROM_WIN32(::GetLastError()));
}
this->ProcToken.Attach(newToken);
if(::CreatePrivateObjectSecurity(NULL, OldClass.ppSD, &this->ppSD, FALSE,
this->ProcToken.GetHandle(), &g_GenericMapping) != TRUE)
{
throw ATL::CAtlException(HRESULT_FROM_WIN32(::GetLastError()));
}
}
double SecureClass::get_len(void) const
{/* Requires ReadLen access. */
if(CheckClassAccess(ReadLen))
{
return len;
}
else
{
throw ATL::CAtlException(0x80070005);
}
}
bool SecureClass::CheckClassAccess(DWORD RightsToCheck) const
{/* Access check */
DWORD GrantedAccess = 0;
BOOL AccessStatus = FALSE, fGenerateOnClose = FALSE;
/* Map away generic rights. */
::MapGenericMask(&RightsToCheck, &g_GenericMapping);
CAccessToken ImpToken;
ImpToken.GetEffectiveToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES);
ImpToken.EnablePrivilege(SE_AUDIT_NAME);
/* enable the SeAuditPrivilege */
if(this->ProcToken.ImpersonateLoggedOnUser())
{
if(::AccessCheckAndAuditAlarm(_T("Custom Class"), this->ProcToken.GetHandle(), _T("SecureClass"),
_T("SecObj1"), ppSD, RightsToCheck, &g_GenericMapping, FALSE, &GrantedAccess,
&AccessStatus, &fGenerateOnClose) == TRUE)
{/* Once the AccessCheck has succeeded, generate the audit alarm */
::ObjectCloseAuditAlarm(_T("Custom Class"), this->ProcToken.GetHandle(), fGenerateOnClose);
}
else
{/* revert to the older AccessCheck */
DWORD PrivilegeLength = 0;
::AccessCheck(this->ppSD, this->ProcToken.GetHandle(), RightsToCheck, &g_GenericMapping, NULL,
&PrivilegeLength, &GrantedAccess, &AccessStatus);
CAutoVectorPtr<BYTE> PrivilegeSet (new BYTE[PrivilegeLength]);
::AccessCheck(this->ppSD, this->ProcToken.GetHandle(), RightsToCheck, &g_GenericMapping,
reinterpret_cast<PRIVILEGE_SET *> (static_cast<BYTE *>(PrivilegeSet)),
&PrivilegeLength, &GrantedAccess, &AccessStatus);
}
ImpToken.DisablePrivilege(SE_AUDIT_NAME);
this->ProcToken.Revert();
}
if(AccessStatus != TRUE) return false;
return GrantedAccess==RightsToCheck;
}
void SecureClass::set_len(double Newlen)
{/* Requires the WriteLen right. */
if(CheckClassAccess(WriteLen))
{
this->len = Newlen;
}
else throw ATL::CAtlException(0x80070005);
}
void SecureClass::set_SecDesc(SECURITY_INFORMATION psi, PSECURITY_DESCRIPTOR pNewSD)
{/* Requires the SetClassSecurity right */
if(CheckClassAccess(WRITE_DAC))
{
::SetPrivateObjectSecurity(psi, pNewSD, &this->ppSD, &g_GenericMapping, this->ProcToken.GetHandle());
}
else throw ATL::CAtlException(0x80070005);
}
SecureClass::~SecureClass()
{
::DestroyPrivateObjectSecurity(&ppSD); ppSD = NULL;
}