|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: si.cpp
//
// This file contains the implementation of the CSecurityInformation
// base class.
//
//--------------------------------------------------------------------------
#include "rshx32.h"
#include <shlapip.h>
#include <dsrole.h>
BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC) { BOOL bStandalone = TRUE; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
//
// Find out if target machine is a standalone machine or joined to
// an NT domain.
//
__try { if (pbIsDC) *pbIsDC = FALSE;
DsRoleGetPrimaryDomainInformation(pszMachine, DsRolePrimaryDomainInfoBasic, (PBYTE*)&pDsRole); } __finally { }
if (NULL != pDsRole) { if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation || pDsRole->MachineRole == DsRole_RoleStandaloneServer) { bStandalone = TRUE; } else bStandalone = FALSE;
if (pbIsDC) { if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController || pDsRole->MachineRole == DsRole_RoleBackupDomainController) { *pbIsDC = TRUE; } }
DsRoleFreeMemory(pDsRole); }
return bStandalone; }
void ProtectACLs(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { SECURITY_DESCRIPTOR_CONTROL wSDControl; DWORD dwRevision; PACL pAcl; BOOL bDefaulted; BOOL bPresent; PACE_HEADER pAce; UINT cAces;
TraceEnter(TRACE_SI, "ProtectACLs");
if (0 == si || NULL == pSD) TraceLeaveVoid(); // Nothing to do
// Get the ACL protection control bits
GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision); wSDControl &= SE_DACL_PROTECTED | SE_SACL_PROTECTED;
if ((si & DACL_SECURITY_INFORMATION) && !(wSDControl & SE_DACL_PROTECTED)) { wSDControl |= SE_DACL_PROTECTED; pAcl = NULL; GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted);
// Theoretically, modifying the DACL in this way can cause it to be
// no longer canonical. However, the only way this can happen is if
// there is an inherited Deny ACE and a non-inherited Allow ACE.
// Since this function is only called for root objects, this means
// a) the server DACL must have a Deny ACE and b) the DACL on this
// object must have been modified later. But if the DACL was
// modified through the UI, then we would have eliminated all of the
// Inherited ACEs already. Therefore, it must have been modified
// through some other means. Considering that the DACL originally
// inherited from the server never has a Deny ACE, this situation
// should be extrememly rare. If it ever does happen, the ACL
// Editor will just tell the user that the DACL is non-canonical.
//
// Therefore, let's ignore the possibility here.
if (NULL != pAcl) { for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl); cAces > 0; --cAces, pAce = (PACE_HEADER)NextAce(pAce)) { pAce->AceFlags &= ~INHERITED_ACE; } } }
if ((si & SACL_SECURITY_INFORMATION) && !(wSDControl & SE_SACL_PROTECTED)) { wSDControl |= SE_SACL_PROTECTED; pAcl = NULL; GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefaulted);
if (NULL != pAcl) { for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl); cAces > 0; --cAces, pAce = (PACE_HEADER)NextAce(pAce)) { pAce->AceFlags &= ~INHERITED_ACE; } } }
SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED | SE_SACL_PROTECTED, wSDControl);
TraceLeaveVoid(); }
CSecurityInformation::CSecurityInformation(SE_OBJECT_TYPE seType) : m_cRef(1), m_seType(seType), m_hwndOwner(NULL),m_ResourceManager(NULL),m_bIsStandAlone(FALSE) { InterlockedIncrement(&g_cRefThisDll); AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT, NULL, NULL, NULL, L"Dummy", &m_ResourceManager );
}
CSecurityInformation::~CSecurityInformation() { LocalFreeDPA(m_hItemList); LocalFreeString(&m_pszObjectName); LocalFreeString(&m_pszServerName); AuthzFreeResourceManager(m_ResourceManager);
ASSERT( 0 != g_cRefThisDll ); InterlockedDecrement(&g_cRefThisDll); }
STDMETHODIMP CSecurityInformation::Initialize(HDPA hItemList, DWORD dwFlags, LPTSTR pszServer, LPTSTR pszObject) { TraceEnter(TRACE_SI, "CSecurityInformation::Initialize"); TraceAssert(hItemList != NULL); TraceAssert(DPA_GetPtrCount(hItemList) > 0); TraceAssert(pszObject != NULL); TraceAssert(m_pszObjectName == NULL); // only initialize once
m_hItemList = hItemList; m_dwSIFlags = dwFlags; m_pszServerName = pszServer; m_pszObjectName = pszObject; m_bIsStandAlone = IsStandalone(pszServer, NULL);
TraceLeaveResult(S_OK); }
///////////////////////////////////////////////////////////
//
// IUnknown methods
//
///////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CSecurityInformation::AddRef() { return ++m_cRef; }
STDMETHODIMP_(ULONG) CSecurityInformation::Release() { if (--m_cRef == 0) { delete this; return 0; }
return m_cRef; }
STDMETHODIMP CSecurityInformation::QueryInterface(REFIID riid, LPVOID FAR* ppv) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation)) { *ppv = (LPSECURITYINFO)this; m_cRef++; return S_OK; } else if (IsEqualIID(riid, IID_IEffectivePermission)) { *ppv = (LPEFFECTIVEPERMISSION)this; m_cRef++; return S_OK; } else if((m_seType != SE_PRINTER) && IsEqualIID(riid, IID_ISecurityObjectTypeInfo)) { *ppv = (LPSecurityObjectTypeInfo)this; m_cRef++; return S_OK; } else { *ppv = NULL; return E_NOINTERFACE; } }
///////////////////////////////////////////////////////////
//
// ISecurityInformation methods
//
///////////////////////////////////////////////////////////
STDMETHODIMP CSecurityInformation::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo) { TraceEnter(TRACE_SI, "CSecurityInformation::GetObjectInformation"); TraceAssert(pObjectInfo != NULL && !IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
pObjectInfo->dwFlags = m_dwSIFlags; pObjectInfo->hInstance = g_hInstance; pObjectInfo->pszServerName = m_pszServerName; pObjectInfo->pszObjectName = m_pszObjectName;
TraceLeaveResult(S_OK); }
STDMETHODIMP CSecurityInformation::GetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD, BOOL fDefault) { HRESULT hr = S_OK; LPTSTR pszItem;
TraceEnter(TRACE_SI, "CSecurityInformation::GetSecurity"); TraceAssert(si != 0); TraceAssert(ppSD != NULL);
*ppSD = NULL;
//Default security descriptor not supported
if (fDefault) ExitGracefully(hr, E_NOTIMPL, "Default security descriptor not supported");
// Get the name of the first item
pszItem = (LPTSTR)DPA_GetPtr(m_hItemList, 0); if (NULL == pszItem) ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
hr = ReadObjectSecurity(pszItem, si, ppSD);
// If this is a Root object, then we pretend that the ACLs are
// always protected and no ACEs are inherited.
if (SUCCEEDED(hr) && (m_dwSIFlags & SI_NO_ACL_PROTECT)) ProtectACLs(si & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), *ppSD);
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CSecurityInformation::SetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { HRESULT hr = S_OK; HCURSOR hcurPrevious = (HCURSOR)INVALID_HANDLE_VALUE; UINT cItems; int i;
TraceEnter(TRACE_SI, "CSecurityInformation::SetSecurity"); TraceAssert(si != 0); TraceAssert(pSD != NULL);
if (NULL == m_hItemList) ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
hcurPrevious = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Apply the new permissions to every item in the list
//
for (i = 0; i < DPA_GetPtrCount(m_hItemList); i++) { LPTSTR pszItem = (LPTSTR)DPA_FastGetPtr(m_hItemList, i); hr = WriteObjectSecurity(pszItem, si, pSD); FailGracefully(hr, "Unable to write new security descriptor"); if (IsFile()) // If this is a file, delete it's thumbnail from the database, it will get put back if appropriate
{ DeleteFileThumbnail(pszItem); } }
exit_gracefully:
// Restore previous cursor
if (hcurPrevious != INVALID_HANDLE_VALUE) SetCursor(hcurPrevious);
TraceLeaveResult(hr); }
STDMETHODIMP CSecurityInformation::PropertySheetPageCallback(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage) { if (SI_PAGE_PERM == uPage) { switch (uMsg) { case PSPCB_SI_INITDIALOG: do { m_hwndOwner = hwnd; } while (hwnd = GetParent(hwnd));
break;
case PSPCB_RELEASE: m_hwndOwner = NULL; break; } } return S_OK; }
STDMETHODIMP CSecurityInformation::ReadObjectSecurity(LPCTSTR pszObject, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD) { DWORD dwErr;
TraceEnter(TRACE_SI, "CSecurityInformation::ReadObjectSecurity"); TraceAssert(pszObject != NULL); TraceAssert(si != 0); TraceAssert(ppSD != NULL);
//
// This is kinda screwy. The new APIs are being removed from NT5, but have
// already been added to NT4 SP4. The old APIs have new functionality on NT5,
// but not on NT4 SPx. Since we need the new functionality (auto-inheritance),
// we have to call the new (defunct) API on NT4 and the old API on NT5.
//
dwErr = GetNamedSecurityInfo((LPTSTR)pszObject, m_seType, si, NULL, NULL, NULL, NULL, ppSD);
TraceLeaveResult(HRESULT_FROM_WIN32(dwErr)); }
STDMETHODIMP CSecurityInformation::WriteObjectSecurity(LPCTSTR pszObject, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { DWORD dwErr;
TraceEnter(TRACE_SI, "CSecurityInformation::WriteObjectSecurity"); TraceAssert(pszObject != NULL); TraceAssert(si != 0); TraceAssert(pSD != NULL);
//
// This is kinda screwy. The new APIs are being removed from NT5, but have
// already been added to NT4 SP4. The old APIs have new functionality on NT5,
// but not on NT4 SPx. Since we need the new functionality (auto-inheritance),
// we have to call the new (defunct) API on NT4 and the old API on NT5.
//
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0; DWORD dwRevision; PSID psidOwner = NULL; PSID psidGroup = NULL; PACL pDacl = NULL; PACL pSacl = NULL; BOOL bDefaulted; BOOL bPresent;
//
// Get pointers to various security descriptor parts for
// calling SetNamedSecurityInfo
//
GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision); GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted); GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted); GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted); GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted);
if (si & DACL_SECURITY_INFORMATION) { if (wSDControl & SE_DACL_PROTECTED) si |= PROTECTED_DACL_SECURITY_INFORMATION; else si |= UNPROTECTED_DACL_SECURITY_INFORMATION; } if (si & SACL_SECURITY_INFORMATION) { if (wSDControl & SE_SACL_PROTECTED) si |= PROTECTED_SACL_SECURITY_INFORMATION; else si |= UNPROTECTED_SACL_SECURITY_INFORMATION; }
dwErr = SetNamedSecurityInfo((LPTSTR)pszObject, m_seType, si, psidOwner, psidGroup, pDacl, pSacl);
TraceLeaveResult(HRESULT_FROM_WIN32(dwErr)); }
OBJECT_TYPE_LIST g_DefaultOTL[] = { {0, 0, (LPGUID)&GUID_NULL}, }; BOOL SkipLocalGroup(LPCWSTR pszServerName, PSID psid) {
SID_NAME_USE use; WCHAR szAccountName[MAX_PATH]; WCHAR szDomainName[MAX_PATH]; DWORD dwAccountLen = MAX_PATH; DWORD dwDomainLen = MAX_PATH;
if(LookupAccountSid(pszServerName, psid, szAccountName, &dwAccountLen, szDomainName, &dwDomainLen, &use)) { if(use == SidTypeWellKnownGroup) return TRUE; }
//Built In sids have first subauthority of 32 ( s-1-5-32 )
//
if((*(GetSidSubAuthorityCount(psid)) >= 1 ) && (*(GetSidSubAuthority(psid,0)) == 32)) return TRUE;
return FALSE; }
STDMETHODIMP CSecurityInformation::GetEffectivePermission(const GUID* pguidObjectType, PSID pUserSid, LPCWSTR pszServerName, PSECURITY_DESCRIPTOR pSD, POBJECT_TYPE_LIST *ppObjectTypeList, ULONG *pcObjectTypeListLength, PACCESS_MASK *ppGrantedAccessList, ULONG *pcGrantedAccessListLength) {
AUTHZ_RESOURCE_MANAGER_HANDLE RM = NULL; //Used for access check
AUTHZ_CLIENT_CONTEXT_HANDLE CC = NULL; LUID luid = {0xdead,0xbeef}; AUTHZ_ACCESS_REQUEST AReq; AUTHZ_ACCESS_REPLY AReply; HRESULT hr = S_OK; DWORD dwFlags;
TraceEnter(TRACE_SI, "CDSSecurityInfo::GetEffectivePermission"); TraceAssert(pUserSid && IsValidSecurityDescriptor(pSD)); TraceAssert(ppObjectTypeList != NULL); TraceAssert(pcObjectTypeListLength != NULL); TraceAssert(ppGrantedAccessList != NULL); TraceAssert(pcGrantedAccessListLength != NULL);
AReq.ObjectTypeList = g_DefaultOTL; AReq.ObjectTypeListLength = ARRAYSIZE(g_DefaultOTL); AReply.GrantedAccessMask = NULL; AReply.Error = NULL;
//Get RM
if( (RM = GetAUTHZ_RM()) == NULL ) ExitGracefully(hr, E_UNEXPECTED, "LocalAlloc failed");
//Initialize the client context
BOOL bSkipLocalGroup = SkipLocalGroup(pszServerName, pUserSid); if( !AuthzInitializeContextFromSid(bSkipLocalGroup? AUTHZ_SKIP_TOKEN_GROUPS :0, pUserSid, RM, NULL, luid, NULL, &CC) ) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "AuthzInitializeContextFromSid Failed"); }
//Do the Access Check
AReq.DesiredAccess = MAXIMUM_ALLOWED; AReq.PrincipalSelfSid = NULL; AReq.OptionalArguments = NULL;
AReply.ResultListLength = AReq.ObjectTypeListLength; AReply.SaclEvaluationResults = NULL; if( (AReply.GrantedAccessMask = (PACCESS_MASK)LocalAlloc(LPTR, sizeof(ACCESS_MASK)*AReply.ResultListLength) ) == NULL ) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc"); if( (AReply.Error = (PDWORD)LocalAlloc(LPTR, sizeof(DWORD)*AReply.ResultListLength)) == NULL ) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc"); if( !AuthzAccessCheck(0, CC, &AReq, NULL, pSD, NULL, 0, &AReply, NULL) ) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "AuthzAccessCheck Failed"); }
exit_gracefully:
if(CC) AuthzFreeContext(CC); if(!SUCCEEDED(hr)) { if(AReply.GrantedAccessMask) LocalFree(AReply.GrantedAccessMask); if(AReply.Error) LocalFree(AReply.Error); AReply.Error = NULL; AReply.GrantedAccessMask = NULL; } else { *ppObjectTypeList = AReq.ObjectTypeList; *pcObjectTypeListLength = AReq.ObjectTypeListLength; *ppGrantedAccessList = AReply.GrantedAccessMask; *pcGrantedAccessListLength = AReq.ObjectTypeListLength; }
TraceLeaveResult(hr); }
|