/**
* This code is by OShah. all code will have the following licence.
* Copyright Shexec32. All code bears the following licence:
**/
/**
* Copyright Shexec32 2004-2005. All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
**/
#include "SecurityCore.h"
STDMETHODIMP_(ULONG)
CObjSecurity::AddRef(void)
{/** IUnknown methods **/
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG)
CObjSecurity::Release(void)
{/* IUnknown */
if (::InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CObjSecurity::QueryInterface(REFIID riid, void ** ppv)
{/** We support IUnknown, ISecurityInformation, IEffectivePermission, ISecurityObjectTypeInfo,
* ISecurityInformation2.
**/
if (::IsEqualIID(riid, IID_IUnknown))
{
*ppv = this;
AddRef();
return S_OK;
}
if(::IsEqualIID(riid, IID_ISecurityInformation))
{
*ppv = dynamic_cast<ISecurityInformation *>(this);
AddRef();
return S_OK;
}
if (::IsEqualIID(riid, IID_IEffectivePermission))
{
*ppv = dynamic_cast<IEffectivePermission *>(this);
AddRef();
return S_OK;
}
if( ::IsEqualIID(riid, IID_ISecurityObjectTypeInfo))
{
*ppv = dynamic_cast<ISecurityObjectTypeInfo *>(this);
AddRef();
return S_OK;
}
/** Our support of ISecurityInformation2 is broken. disable this
* if( ::IsEqualIID(riid, IID_ISecurityInformation2))
* {
* *ppv = dynamic_cast<ISecurityInformation2 *>(this);
* AddRef();
* return S_OK;
* }
**/
*ppv = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP
CObjSecurity::PropertySheetPageCallback(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage)
{/* This is our chance to save off the handles to the property sheets. */
#if 0
if(uPage != SI_PAGE_PERM && uPage != SI_PAGE_ADVPERM)
/* only act if the basic or 1st advanced sheet is shown */
return S_OK;
switch(uMsg)
{/* Get the Window handle */
case PSPCB_SI_INITDIALOG:
{/* Save off the window handle */
vec_OurhWnd.push_front(hwnd);
}
case PSPCB_RELEASE:
{
vec_OurhWnd.pop_front();
}
default:
break;
}
#endif
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(uPage);
/** These window handles are unreliable. Instead, I'll use GetLastActivePopup, instead of maintaining
* a list of hWnds
**/
return S_OK;
}
STDMETHODIMP
CObjSecurity::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
{/** ISecurityInformation methods **/
/* We are expected to fill out pObjectInfo */
pObjectInfo->dwFlags = m_dwSIFlags;
pObjectInfo->hInstance = g_hInst;
pObjectInfo->pszServerName = this->ServerName.get();
if(m_pszObjectName.size() == 1)
{/* We must strip the path from the filename. */
std::list<sized_array<TCHAR> >::const_iterator Iter = m_pszObjectName.begin();
std::basic_string<TCHAR> ObjName = Iter->get();
size_t lastSlash = ObjName.find_last_of(_T("\\/")); /* Find the last slash */
if(lastSlash > ObjName.size()) lastSlash = 0;
if(ObjName.size() < 4) lastSlash = 0; /* Root folder hack. */
else lastSlash += 1; /* We need to set the pointer to Just after the slash */
pObjectInfo->pszObjectName = Iter->get() + lastSlash;
}
else
{/* use a constant string for multiple objects. */
pObjectInfo->pszObjectName = L"Multiple Objects";
}
return S_OK;
}
STDMETHODIMP
CObjSecurity::GetAccessRights(const GUID* /*pguidObjectType*/, DWORD /*dwFlags*/,
PSI_ACCESS *ppAccesses, ULONG *pcAccesses, ULONG *piDefaultAccess)
{/* This where we send out the Big Structure at the top of this file. */
*ppAccesses = const_cast<SI_ACCESS *>(g_siObjAccesses);
*pcAccesses = gc_siObjAccesses;
*piDefaultAccess = 2; /* Set Read access as default. */
return S_OK;
}
STDMETHODIMP
CObjSecurity::MapGeneric(const GUID* /*pguidObjectType*/, UCHAR * /*pAceFlags*/, ACCESS_MASK *pmask)
{/* This is needed by ISecurityInformation to get GENERIC_*. We need to call MapGenericMask */
GENERIC_MAPPING ObjMap =
{
READ_CONTROL | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA | FILE_APPEND_DATA,
READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_EXECUTE,
FILE_ALL_ACCESS
};
::MapGenericMask(pmask, &ObjMap);
return S_OK;
}
STDMETHODIMP
CObjSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes)
{/* This is where we feed in the PSI_INHERIT_TYPEs. (The folder/subfolder/file thingies) */
*ppInheritTypes = const_cast<SI_INHERIT_TYPE *>(g_InheritTypes);
*pcInheritTypes = gc_InheritTypes;
return S_OK;
}
STDMETHODIMP
CObjSecurity::GetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD, BOOL fDefault)
{/* The first object should be enough to get the security of the object. */
DWORD dwErr = 0;
*ppSD = NULL;
PSECURITY_DESCRIPTOR pSDRes = NULL;
PrivMgr SaclPriv(SE_SECURITY_NAME, &this->PrivClassImpl);
if(si & SACL_SECURITY_INFORMATION)
{/* Turnon the SeSecurityPrivilege */
SaclPriv.TurnOn();
}
if (fDefault)
{/* Assume that required privileges have already been enabled */
std::list<sized_array<TCHAR> >::const_iterator Iter = this->m_pszObjectName.begin();
std::basic_string<TCHAR> ObjName = Iter->get();
std::basic_string<TCHAR> PrimaryUser = _T("");
this->GetDefaultSecurity(ObjName, PrimaryUser);
::SetLastError(ERROR_SUCCESS);
/* ACLUI will localfree the SD for us. */
::ConvertStringSecurityDescriptorToSecurityDescriptor(PrimaryUser.c_str(), SDDL_REVISION_1, &pSDRes, 0);
dwErr = ::GetLastError();
if(dwErr == ERROR_SUCCESS) *ppSD = pSDRes;
return HRESULT_FROM_WIN32(dwErr);
}
::SetLastError(ERROR_SUCCESS);
{/* ACLUI will free ppSD for us. */
std::list<sized_array<TCHAR> >::const_iterator Iter = this->m_pszObjectName.begin();
dwErr = ::GetNamedSecurityInfo(Iter->get(),
this->SeObjectType, si, NULL, NULL, NULL, NULL, &pSDRes);
if(dwErr == ERROR_SUCCESS) *ppSD = pSDRes;
}
return HRESULT_FROM_WIN32(dwErr);
}
STDMETHODIMP
CObjSecurity::GetInheritSource(SECURITY_INFORMATION psi, PACL pAcl, PINHERITED_FROM *ppInheritArray)
{/** This method will get the information contained in psi and pAcl to fill out a INHERITED_FROM struct
* with an array of inheritees.
**/
DWORD dwErr = 0;
size_t i = 0, dwSize = 0;
PINHERITED_FROM InheritTmp = reinterpret_cast<PINHERITED_FROM>
(::LocalAlloc(LPTR, (1 + pAcl->AceCount) * sizeof(INHERITED_FROM)));
GENERIC_MAPPING ObjMap =
{/* This is a copy of ObjMap from this->MapGeneric. */
FILE_GENERIC_READ,
FILE_GENERIC_WRITE,
FILE_GENERIC_EXECUTE,
FILE_ALL_ACCESS
};
{/* Allocate space for the GetInheritanceSource (pAcl will tell us how many entries we need.) */
BOOL Container = (this->m_dwSIFlags & SI_CONTAINER) ? TRUE : FALSE;
/* Find out again if this object is a container */
std::list<sized_array<TCHAR> >::const_iterator Iter = this->m_pszObjectName.begin();
dwErr = ::GetInheritanceSource(Iter->get(),
this->SeObjectType, psi, Container, NULL, 0, pAcl, NULL, &ObjMap, InheritTmp);
if(dwErr != ERROR_SUCCESS)
{/* Free resources then exit. */
::LocalFree(InheritTmp); InheritTmp = NULL;
return HRESULT_FROM_WIN32(dwErr);
}
if(InheritTmp->AncestorName == NULL)
{/* An empty list, return this empty list. */
*ppInheritArray = InheritTmp;
return S_OK;
}
}
for(i = 0; i < pAcl->AceCount; i++)
{/* Get the total size needed to hold all those names. */
const std::basic_string<TCHAR> &GenName = (InheritTmp[i].AncestorName == NULL) ?
_T("Parent") : InheritTmp[i].AncestorName;
dwSize += GenName.size() + 1; /* We want to separate each string when we exit out. */
}
PINHERITED_FROM InheritResult = reinterpret_cast<PINHERITED_FROM>
(::LocalAlloc(LPTR, (1 + pAcl->AceCount) * sizeof(INHERITED_FROM) + dwSize * sizeof(TCHAR)));
if( InheritResult == NULL)
{/** We're going to use the setargv method to allocate a 2 dimensional array with one allocation.
* The array segment will contain the PINHERITED_FROM array. The Data segment will contain
* the list of names for AncestorName.
**/
::FreeInheritedFromArray(InheritTmp, pAcl->AceCount, NULL);
::LocalFree(InheritTmp); InheritTmp = NULL;
return E_OUTOFMEMORY;
}
{/* Copy this array into a safe location (because WE must free this array, yet it must be passed to ACLUI). */
TCHAR *DataPtr = reinterpret_cast<TCHAR *>(reinterpret_cast<BYTE *>(InheritResult) +
pAcl->AceCount * sizeof(INHERITED_FROM));
for(i = 0; i < pAcl->AceCount; i++)
{/* Copy each AncestorName into the destination data segment */
const std::basic_string<TCHAR> &GenName = (InheritTmp[i].AncestorName == NULL) ?
_T("Parent") : InheritTmp[i].AncestorName; /* Proxy Object (for _tcslen) */
CopyString(GenName, DataPtr, GenName.size());
//GenName.copy(DataPtr, GenName.size(), 0);
/* Update the array segment with this new data. */
InheritResult[i].GenerationGap = InheritTmp[i].GenerationGap;
InheritResult[i].AncestorName = DataPtr;
/* This name is now in the data segment. Iterate to the next pointer. */
DataPtr += GenName.size() + 1;
}
}
/* Cleanup resources */
::FreeInheritedFromArray(InheritTmp, pAcl->AceCount, NULL);
::LocalFree(InheritTmp); InheritTmp = NULL;
/* Possible leak? */
*ppInheritArray = InheritResult;
return HRESULT_FROM_WIN32(dwErr);
}
STDMETHODIMP
CObjSecurity::GetEffectivePermission(const GUID * /*pguidObjectType*/, PSID pUserSid, LPCWSTR /*pszServerName*/,
PSECURITY_DESCRIPTOR pSD, POBJECT_TYPE_LIST* ppObjectTypeList, ULONG* pcObjectTypeListLength,
PACCESS_MASK* ppGrantedAccessList, ULONG* pcGrantedAccessListLength)
{/** This method is called by GetEffectivePermission when the user uses ACLUI's frontend for GetEffectiveRightsFromAcl().
* We are supplied the User SID, the server for that SID, and the SD. We must fill the object list and the
* grantedAccessList (and their sizes).
**/
DWORD dwErr = 0;
BOOL AclPresent = FALSE, AclDefaulted = FALSE;
PACCESS_MASK AccessRights = NULL;
PACL Dacl = NULL;
*ppObjectTypeList = const_cast<OBJECT_TYPE_LIST *>(g_DefaultOTL);
*pcObjectTypeListLength = 1;
::SetLastError(ERROR_SUCCESS);
/* Get the Acl from the SD given */
dwErr = ::GetSecurityDescriptorDacl(pSD, &AclPresent, &Dacl, &AclDefaulted);
if(Dacl != NULL && dwErr == TRUE)
{/* Make a trustee from the SID given */
TRUSTEE Trustee = {0};
::BuildTrusteeWithSid(&Trustee, pUserSid);
/* Copy AccessRights to a LocalAlloc ptr. ACLUI will free it. */
AccessRights = reinterpret_cast<PACCESS_MASK>(::LocalAlloc(LPTR, sizeof(PACCESS_MASK) + sizeof(ACCESS_MASK)));
if(AccessRights == NULL)
{
return E_OUTOFMEMORY;
}
dwErr = ::GetEffectiveRightsFromAcl(Dacl, &Trustee, AccessRights);
if(dwErr != ERROR_SUCCESS)
{/* And call the required API. */
::LocalFree(AccessRights); AccessRights = NULL;
return HRESULT_FROM_WIN32(dwErr);
}
*ppGrantedAccessList = AccessRights;
*pcGrantedAccessListLength = 1;
return S_OK;
}
return HRESULT_FROM_WIN32(dwErr);
}
STDMETHODIMP
CObjSecurity::LookupSids(ULONG /* cSids */, PSID * /* rgpSids */, LPDATAOBJECT * /* ppdo */)
{/* ISecurityInformation2. Let ACLUI handle this work. */
return E_NOTIMPL;
}
BOOL STDMETHODCALLTYPE
CObjSecurity::IsDaclCanonical(PACL)
{/* We'll always return TRUE (assume the dacl is ordered). */
return TRUE;
}