//********************************************************* // // Copyright (c) Microsoft. All rights reserved. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. // //********************************************************* // // This file contains the definitions for all of the ISecurityInformation // functions from CSecInfo. This got its own file because the implementation // of ISecurityInformation is the largest of the interfaces. // #include "CSecInfo.h" #include "utility.h" #include "authz.h" #include #include "sddl.h" #include IFACEMETHODIMP CSecInfo::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo) { Resource *currentResource; // SI_OBJECT_INFO: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379605(v=vs.85).aspx m_dwSIFlags = 0 | SI_ADVANCED // The "advanced" button is displayed on the basic // security property page | SI_EDIT_PERMS // The basic security property page always allows // basic editing of the object's DACL | SI_EDIT_OWNER // This lets you change the owner on the advanced page | SI_PAGE_TITLE // Use pObjectInfo->pszPageTitle for the basic page's // title | SI_VIEW_ONLY // Displays a read-only version of the ACL Editor // dialog boxes. This is required if you're // implementing ISecurityInformation3. | SI_EDIT_EFFECTIVE | SI_ENABLE_EDIT_ATTRIBUTE_CONDITION ; currentResource = m_resources[m_editingResource]; if ( currentResource->IsContainer() != FALSE) { // This will make ACL UI show the inheritance controls m_dwSIFlags |= SI_CONTAINER; } pObjectInfo->dwFlags = m_dwSIFlags; pObjectInfo->hInstance = 0; pObjectInfo->pszServerName = nullptr; // ACL Editor won't free this, so we don't need to make a copy pObjectInfo->pszObjectName = currentResource->GetName(); pObjectInfo->pszPageTitle = L"Forums Resource Manager"; return S_OK; } IFACEMETHODIMP CSecInfo::GetSecurity( SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD, BOOL fDefault) { BOOL bResult = 0; HRESULT hr = S_OK; DWORD errorCode = 0; Resource *currentResource = m_resources[m_editingResource]; ULONG defaultSecurityDescriptorSize = 0; // This may be the default SD, or it may // be the SD on the resource we're editing PWSTR sdToEdit = NULL; if ( fDefault ) { hr = AllocAndCopyString(m_defaultSecurityDescriptorSddl, &sdToEdit); FailGracefully(hr, L"AllocAndCopyString"); } else { hr = AllocAndCopyString( const_cast(currentResource->GetSD()), &sdToEdit); FailGracefully(hr, L"AllocAndCopyString"); } if ( IS_FLAG_SET(si, DACL_SECURITY_INFORMATION) || IS_FLAG_SET(si, OWNER_SECURITY_INFORMATION) || IS_FLAG_SET(si, GROUP_SECURITY_INFORMATION) ) { // The following function will populate the entire SD. bResult = ConvertStringSecurityDescriptorToSecurityDescriptor( sdToEdit, SDDL_REVISION_1, ppSD, &defaultSecurityDescriptorSize); FailGracefullyGLE( bResult, L"ConvertStringSecurityDescriptorToSecurityDescriptor"); } exit_gracefully: LocalFree(sdToEdit); return hr; } IFACEMETHODIMP CSecInfo::SetSecurity( SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { BOOL bResult = 0; DWORD errorCode = 0; HRESULT hr = S_OK; PACL pDestDacl = nullptr; BOOL bDaclPresent = 0; BOOL bDaclDefaulted = 0; PACL pSourceDacl = nullptr; DWORD dwSizeNeeded; SECURITY_DESCRIPTOR_CONTROL sdControl; DWORD dwRevision; int parentIndex; PSECURITY_DESCRIPTOR pSDOfParent; PSID group; BOOL bGroupDefaulted = 0; PSID owner; BOOL bOwnerDefaulted = 0; PWSTR stringSD; ULONG stringSDLen = 0; SECURITY_DESCRIPTOR_CONTROL currentObjectSDControl; PSECURITY_DESCRIPTOR absoluteCurrentSD; Resource *currentResource = m_resources[m_editingResource]; hr = ConvertStringToAbsSD(currentResource->GetSD(), &absoluteCurrentSD); FailGracefully(hr, L"ConvertStringToAbsSD"); if ( IS_FLAG_SET(si, DACL_SECURITY_INFORMATION) ) { bResult = GetSecurityDescriptorDacl( pSD, &bDaclPresent, &pSourceDacl, &bDaclDefaulted ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl"); bResult = GetSecurityDescriptorDacl( absoluteCurrentSD, &bDaclPresent, &pDestDacl, &bDaclDefaulted ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl"); if ( pDestDacl == nullptr ) { // Align sizeNeeded to a DWORD dwSizeNeeded = (sizeof(ACL) + (sizeof(DWORD) - 1)) & 0xfffffffc; pDestDacl = (PACL)LocalAlloc(LPTR, dwSizeNeeded); if ( pDestDacl == nullptr ) { wprintf(L"LocalAlloc failed.\n"); hr = E_OUTOFMEMORY; goto exit_gracefully; } bResult = InitializeAcl(pDestDacl, dwSizeNeeded, ACL_REVISION); FailGracefullyGLE(bResult, L"InitializeAcl"); } // Before doing anything else, we need to change the protected // bit in case we end up reenabling inheritance. // If the 'P' flag was set, e.g. D:PAR(A;CIIO;FA;;;WD) // then we need to remove all inherited entries bResult = GetSecurityDescriptorControl( pSD, &sdControl, &dwRevision ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorControl"); bResult = GetSecurityDescriptorControl( absoluteCurrentSD, ¤tObjectSDControl, &dwRevision ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorControl"); BOOL currentObjectWasProtected = IS_FLAG_SET(currentObjectSDControl, SE_DACL_PROTECTED) ? TRUE : FALSE; // Now that we've gotten the SE_DACL_PROTECTED bit off of the current // object, we can set it to what it needs to be. We needed to capture // it in the case that we're reenabling inheritance. bResult = SetSecurityDescriptorControl( absoluteCurrentSD, SE_DACL_PROTECTED, IS_FLAG_SET(sdControl, SE_DACL_PROTECTED) ? SE_DACL_PROTECTED : 0 ); FailGracefullyGLE(bResult, L"SetSecurityDescriptorControl"); if ( IS_FLAG_SET(sdControl, SE_DACL_PROTECTED) ) { hr = RemoveAllInheritedAces( &pDestDacl ); FailGracefully(hr, L"RemoveAllInheritedAces"); } else { // The user reenabled inheritance (i.e. didn't pass in // SE_DACL_PROTECTED, but the object used to have that flag). if ( currentObjectWasProtected != FALSE ) { // This means we need to call SetSecurityOfChildren on the // parent. This is why we disabled the SE_DACL_PROTECTED flag // already - otherwise the function would exit immediately. parentIndex = currentResource->GetParentIndex(); if ( parentIndex != NONEXISTENT_OBJECT ) { Resource *parentResource = m_resources[parentIndex]; // Because we're keeping SDs as strings, we need to do // a bit of hackery here to set up for SetSecurityOfChildren. // First, save the current security descriptor to where // SetSecurityOfChildren can pick it up { bResult = ConvertSecurityDescriptorToStringSecurityDescriptor( absoluteCurrentSD, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, &stringSD, &stringSDLen ); FailGracefullyGLE(bResult, L"ConvertSecurityDescriptorToStringSecurityDescriptor"); currentResource->FreeSD(); currentResource->SetSD(stringSD); stringSD = nullptr; } hr = ConvertStringToAbsSD( parentResource->GetSD(), &pSDOfParent); FailGracefully(hr, L"ConvertStringToAbsSD"); hr = SetSecurityOfChildren( parentIndex, DACL_SECURITY_INFORMATION, pSDOfParent); FailGracefully(hr, L"SetSecurityOfChildren"); // Now, the current resource's SD will be set to what we want... // so we need to make sure we're working on that by making // absoluteCurrentSD into that. hr = ConvertStringToAbsSD( currentResource->GetSD(), &absoluteCurrentSD); FailGracefully(hr, L"ConvertStringToAbsSD"); // The DACL probably just changed bResult = GetSecurityDescriptorDacl( absoluteCurrentSD, &bDaclPresent, &pDestDacl, &bDaclDefaulted ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl"); } } } hr = AddAllAcesFromAcl(pSourceDacl, &pDestDacl, TRUE); FailGracefully(hr, L"AddAllAcesFromAcl"); // Finally, remove the explicit ACEs that don't appear in pSD. // These are ACEs that used to be on the DACL, but the user just // removed. hr = RemoveExplicitUniqueAces( pSourceDacl, &pDestDacl ); FailGracefully(hr, L"RemoveExplicitUniqueAces"); hr = OrderDacl( m_editingResource, &pDestDacl ); FailGracefully(hr, L"OrderDacl"); bResult = SetSecurityDescriptorDacl( absoluteCurrentSD, true, pDestDacl, bDaclDefaulted ); FailGracefullyGLE(bResult, L"SetSecurityDescriptorDacl"); pDestDacl = nullptr; } if ( IS_FLAG_SET(si, GROUP_SECURITY_INFORMATION) ) { bResult = GetSecurityDescriptorGroup( pSD, &group, &bGroupDefaulted ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorGroup"); bResult = SetSecurityDescriptorGroup( absoluteCurrentSD, group, bGroupDefaulted ); FailGracefullyGLE(bResult, L"SetSecurityDescriptorGroup"); } if ( IS_FLAG_SET(si, OWNER_SECURITY_INFORMATION) ) { bResult = GetSecurityDescriptorOwner( pSD, &owner, &bOwnerDefaulted ); FailGracefullyGLE(bResult, L"GetSecurityDescriptorOwner"); bResult = SetSecurityDescriptorOwner( absoluteCurrentSD, owner, bOwnerDefaulted ); FailGracefullyGLE(bResult, L"SetSecurityDescriptorOwner"); } // Finally, convert whatever changes we made to the absolute SD back to a string bResult = ConvertSecurityDescriptorToStringSecurityDescriptor( absoluteCurrentSD, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, &stringSD, &stringSDLen ); FailGracefullyGLE(bResult, L"ConvertSecurityDescriptorToStringSecurityDescriptor"); currentResource->FreeSD(); currentResource->SetSD(stringSD); stringSD = nullptr; if ( currentResource->IsContainer() != FALSE) { hr = SetSecurityOfChildren(m_editingResource, si, absoluteCurrentSD); FailGracefully(hr, L"SetSecurityOfChildren"); } exit_gracefully: LocalFree(pDestDacl); return hr; } IFACEMETHODIMP CSecInfo::GetAccessRights( const GUID* pguidObjectType, DWORD dwFlags, PSI_ACCESS *ppAccess, ULONG *pcAccesses, ULONG *piDefaultAccess) { UNREFERENCED_PARAMETER(dwFlags); if ( pguidObjectType == nullptr || *pguidObjectType == GUID_NULL ) { *ppAccess = const_cast(m_AccessTable); *pcAccesses = m_AccessTableCount; // This is the index of the default access you want when you're // adding a permission. It ends up indexing m_AccessTable, which // is really g_siForumsAccess, so 0 is Full Control. *piDefaultAccess = m_DefaultAccess; } return S_OK; } // This function requests that the generic access rights in an access mask // be mapped to their corresponding standard and specific access rights. IFACEMETHODIMP CSecInfo::MapGeneric( const GUID *pguidObjectType, UCHAR *pAceFlags, ACCESS_MASK *pMask) { if ( !pAceFlags || !pMask ) { return E_INVALIDARG; } // This sample doesn't include object inheritance, so that bit can be // safely removed. *pAceFlags &= ~OBJECT_INHERIT_ACE; MapGenericMask(pMask, &ObjectMap); UNREFERENCED_PARAMETER(pguidObjectType); return S_OK; } IFACEMETHODIMP CSecInfo::GetInheritTypes( PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes) { if ( m_resources[m_editingResource]->IsContainer() != FALSE) { *ppInheritTypes = siSDKInheritTypes; *pcInheritTypes = ARRAYSIZE(siSDKInheritTypes); return S_OK; } return E_NOTIMPL; } IFACEMETHODIMP CSecInfo::PropertySheetPageCallback( HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage) { UNREFERENCED_PARAMETER(hwnd); UNREFERENCED_PARAMETER(uMsg); UNREFERENCED_PARAMETER(uPage); return E_NOTIMPL; }