|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: acelist.cpp
//
// This file contains the implementation for the advanced ACE list editor
// permission and auditing pages.
//
//--------------------------------------------------------------------------
#include "aclpriv.h"
#include <accctrl.h>
//Functions selects an Item in ListView. It first
//Clears all exisiting selections
VOID SelectSingleItemInLV( HWND hListView, INT iSelected ) { INT cCount = ListView_GetItemCount( hListView ); for( INT i = 0; i < cCount; ++i ) ListView_SetItemState( hListView, i, 0, LVIS_SELECTED | LVIS_FOCUSED );
//Now select the iSelected
ListView_SetItemState( hListView, iSelected, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); return;
}
//This function checks if any of the aces selected in the listbox
//is of type
//type = fAppliedDirect ? Applied Directly on this object :
// Inhereted from parent
BOOL AnySelectedAceofType( HWND hListView, BOOL fAppliedDirect ) { LVITEM lvi = {0}; UINT cSelectedCount = 0; //Number of item selected in listbox
lvi.iItem = -1; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
cSelectedCount = ListView_GetSelectedCount(hListView); while( cSelectedCount-- ) { lvi.iItem = ListView_GetNextItem(hListView, lvi.iItem, LVNI_SELECTED);
if (lvi.iItem != -1) { lvi.lParam = NULL;
ListView_GetItem(hListView, &lvi); if( fAppliedDirect && ( (((PACE)lvi.lParam)->AceFlags & INHERITED_ACE) == 0 ) ) return TRUE; if( !fAppliedDirect && ((PACE)lvi.lParam)->AceFlags & INHERITED_ACE ) return TRUE;
} } return FALSE; }
LPARAM GetSelectedItemData(HWND hListView, int *pIndex) { int iSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
if (pIndex) *pIndex = iSelected;
if (iSelected == -1) return NULL;
LV_ITEM lvi;
lvi.mask = LVIF_PARAM; lvi.iItem = iSelected; lvi.iSubItem = 0; lvi.lParam = NULL;
ListView_GetItem(hListView, &lvi);
return lvi.lParam; }
void SelectListViewItem(HWND hListView, int iSelected) { ListView_SetItemState(hListView, iSelected, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); ListView_EnsureVisible(hListView, iSelected, FALSE); }
void EnsureListViewSelectionIsVisible(HWND hListView) { int iSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); if (-1 != iSelected) ListView_EnsureVisible(hListView, iSelected, FALSE); }
INT_PTR _ConfirmAclProtectProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: Static_SetIcon(GetDlgItem(hDlg, IDC_CONFIRM_ICON), LoadIcon(NULL, IDI_QUESTION)); return TRUE;
case WM_COMMAND: if (BN_CLICKED == GET_WM_COMMAND_CMD(wParam, lParam)) { EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); return TRUE; } break; } return FALSE; }
int ConfirmAclProtect(HWND hwndParent, BOOL bDacl) { return (int)DialogBox(::hModule, MAKEINTRESOURCE(bDacl ? IDD_CONFIRM_DACL_PROTECT : IDD_CONFIRM_SACL_PROTECT), hwndParent, _ConfirmAclProtectProc); }
//
// Context Help IDs.
//
const static DWORD aAceListPermHelpIDs[] = { IDC_ACEL_DETAILS, IDH_ACEL_PERM_DETAILS, IDC_ACEL_ADD, IDH_ACEL_PERM_ADD, IDC_ACEL_REMOVE, IDH_ACEL_PERM_REMOVE, IDC_ACEL_EDIT, IDH_ACEL_PERM_EDIT, IDC_ACEL_RESET, IDH_ACEL_PERM_RESET, IDC_ACEL_DEFAULT_STATIC, IDH_ACEL_PERM_RESET, IDC_ACEL_PROTECT, IDH_ACEL_PERM_PROTECT, IDC_ACEL_DESCRIPTION, IDH_NOHELP, IDC_ACEL_RESET_ACL_TREE, IDH_ACEL_PERM_RESET_ACL_TREE, IDC_ACEL_STATIC, -1, 0, 0 };
const static DWORD aAceListAuditHelpIDs[] = { IDC_ACEL_DETAILS, IDH_ACEL_AUDIT_DETAILS, IDC_ACEL_ADD, IDH_ACEL_AUDIT_ADD, IDC_ACEL_REMOVE, IDH_ACEL_AUDIT_REMOVE, IDC_ACEL_EDIT, IDH_ACEL_AUDIT_EDIT, IDC_ACEL_RESET, IDH_ACEL_AUDIT_RESET, IDC_ACEL_DEFAULT_STATIC, IDH_ACEL_AUDIT_RESET, IDC_ACEL_PROTECT, IDH_ACEL_AUDIT_PROTECT, IDC_ACEL_DESCRIPTION, IDH_NOHELP, IDC_ACEL_RESET_ACL_TREE, IDH_ACEL_AUDIT_RESET_ACL_TREE, IDC_ACEL_STATIC, -1, 0, 0 };
class CAdvancedListPage : public CSecurityPage { private: PSI_ACCESS m_pAccess; ULONG m_cAccesses; PSI_INHERIT_TYPE m_pInheritType; ULONG m_cInheritTypes; int m_iLastColumnClick; int m_iSortDirection; BOOL m_fPageDirty:1; BOOL m_bReadOnly:1; BOOL m_bAuditPolicyOK:1; BOOL m_bWasDenyAcl:1; DWORD m_cInheritableAces;
public: CAdvancedListPage( LPSECURITYINFO psi, SI_PAGE_TYPE siType ) : CSecurityPage(psi, siType), m_iLastColumnClick(-1), m_iSortDirection(1), m_cInheritableAces(0){}
private: virtual BOOL DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); PACL GetACL(PSECURITY_DESCRIPTOR *ppSD, LPBOOL pbProtected, BOOL bDefault); void FillAceList(HWND hListView, PACL pAcl, BOOL bSortList = TRUE); void InitDlg( HWND hDlg ); int AddAce(HWND hListView, PACE_HEADER pAceHeader, int iRow, LPCTSTR pszInheritSource, int level); int AddAce(HWND hListView, PACE pAce, int iRow, LPCTSTR pszInheritSource, int level); LPCTSTR TranslateAceIntoRights(DWORD dwAceFlags, DWORD dwMask, const GUID *pObjectType, const GUID *pInheritedObjectType, LPCTSTR *ppszInheritType); LPCTSTR GetItemString(LPCTSTR pszItem, LPTSTR pszBuffer, UINT ccBuffer); void UpdateButtons(HWND hDlg); //NTRAID#NTBUG9-555470-2002/03/29-hiteshr
HRESULT BuildAcl(HWND hListView, PACL *ppAcl); HRESULT ApplyAudits(HWND hDlg, HWND hListView, BOOL fProtected); HRESULT ApplyPermissions(HWND hDlg, HWND hListView, BOOL fProtected); void OnApply(HWND hDlg, BOOL bClose); void OnAdd(HWND hDlg); void OnRemove(HWND hDlg); void OnReset(HWND hDlg); void OnProtect(HWND hDlg); void OnEdit(HWND hDlg); int AddAcesFromDPA(HWND hListView, HDPA hEntries, int iSelected); void EditAce(HWND hDlg, PACE pAce, BOOL bDeleteSelection, LONG iSelected = MAXLONG); void CheckAuditPolicy(HWND hwndOwner); }; typedef CAdvancedListPage *PADVANCEDLISTPAGE;
int CALLBACK AceListCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int iResult = 0; PACE pAce1 = (PACE)lParam1; PACE pAce2 = (PACE)lParam2; short iColumn = LOWORD(lParamSort); short iSortDirection = HIWORD(lParamSort); LPTSTR psz1 = NULL; LPTSTR psz2 = NULL;
TraceEnter(TRACE_ACELIST, "AceListCompareProc");
if (iSortDirection == 0) iSortDirection = 1;
if (pAce1 && pAce2) { switch (iColumn) { case 0: psz1 = pAce1->GetType(); psz2 = pAce2->GetType(); break; case 1: psz1 = pAce1->GetName(); psz2 = pAce2->GetName(); break;
case 2: psz1 = pAce1->GetAccessType(); psz2 = pAce2->GetAccessType(); break;
case 3: psz1 = pAce1->GetInheritSourceName(); psz2 = pAce2->GetInheritSourceName(); break; case 4: psz1 = pAce1->GetInheritType(); psz2 = pAce2->GetInheritType(); break; }
if (iResult == 0 && psz1 && psz2) { iResult = CompareString(LOCALE_USER_DEFAULT, 0, psz1, -1, psz2, -1) - 2; }
iResult *= iSortDirection; }
TraceLeaveValue(iResult); }
//
//This function is used for cannonical sorting of the list
//
int CALLBACK AceListCompareProcCanno(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int iResult = 0; PACE pAce1 = (PACE)lParam1; PACE pAce2 = (PACE)lParam2; short iColumn = LOWORD(lParamSort); short iSortDirection = HIWORD(lParamSort); LPTSTR psz1 = NULL; LPTSTR psz2 = NULL;
TraceEnter(TRACE_ACELIST, "AceListCompareProc");
if (iSortDirection == 0) iSortDirection = 1;
if (pAce1 && pAce2) { switch (iColumn) { case 0: iResult = pAce1->CompareType(pAce2); // Fall through and use the name to differentiate ACEs of the same type
case 1: psz1 = pAce1->GetName(); psz2 = pAce2->GetName(); break;
}
if (iResult == 0 && psz1 && psz2) { iResult = CompareString(LOCALE_USER_DEFAULT, 0, psz1, -1, psz2, -1) - 2; }
iResult *= iSortDirection; }
TraceLeaveValue(iResult); }
//
// CAdvancedListPage implementation
//
LPCTSTR CAdvancedListPage::TranslateAceIntoRights(DWORD dwAceFlags, DWORD dwMask, const GUID *pObjectType, const GUID *pInheritedObjectType, LPCTSTR *ppszInheritType) { LPCTSTR pszName = NULL; PSI_ACCESS pAccess = m_pAccess; ULONG cAccess = m_cAccesses; UINT iItem;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::TranslateAceIntoRights"); TraceAssert(pObjectType != NULL); TraceAssert(pInheritedObjectType != NULL); TraceAssert(!m_bAbortPage);
// If this ACE applies to a different object type, ask the client
// for the appropriate SI_ACCESS list.
if ((m_siObjectInfo.dwFlags & SI_OBJECT_GUID) && !IsNullGUID(pInheritedObjectType) && !IsSameGUID(pInheritedObjectType, &m_siObjectInfo.guidObjectType)) { ULONG iDefaultAccess; DWORD dwFlags = SI_ADVANCED; if (m_siPageType == SI_PAGE_AUDIT) dwFlags |= SI_EDIT_AUDITS; if (FAILED(m_psi->GetAccessRights(pInheritedObjectType, dwFlags, &pAccess, &cAccess, &iDefaultAccess))) { pAccess = m_pAccess; cAccess = m_cAccesses; } }
if (pAccess && cAccess) { // Look for a name for the mask
for (iItem = 0; iItem < cAccess; iItem++) { if ( dwMask == pAccess[iItem].mask && IsSameGUID(pObjectType, pAccess[iItem].pguid) ) { pszName = pAccess[iItem].pszName; break; } } }
// Look for a name for the inheritance type
if ((m_siObjectInfo.dwFlags & SI_CONTAINER) && ppszInheritType) { // Check these inherit bits for a match
DWORD dwInheritMask = INHERIT_ONLY_ACE | ACE_INHERIT_ALL;
// Don't check INHERIT_ONLY_ACE if the ACE inherit type
// matches the current object
if ((m_siObjectInfo.dwFlags & SI_OBJECT_GUID) && IsSameGUID(&m_siObjectInfo.guidObjectType, pInheritedObjectType)) { dwInheritMask &= ~INHERIT_ONLY_ACE; }
*ppszInheritType = NULL;
for (iItem = 0; iItem < m_cInheritTypes; iItem++) { if ((m_pInheritType[iItem].dwFlags & dwInheritMask) == (ULONG)(dwAceFlags & dwInheritMask) && IsSameGUID(pInheritedObjectType, m_pInheritType[iItem].pguid)) { *ppszInheritType = m_pInheritType[iItem].pszName; break; } } }
TraceLeaveValue(pszName); }
LPCTSTR CAdvancedListPage::GetItemString(LPCTSTR pszItem, LPTSTR pszBuffer, UINT ccBuffer) { TraceEnter(TRACE_ACELIST, "CAdvancedListPage::GetItemString");
if (pszItem == NULL) { LoadString(::hModule, IDS_SPECIAL, pszBuffer, ccBuffer); pszItem = pszBuffer; } else if (IS_INTRESOURCE(pszItem)) { if (LoadString(m_siObjectInfo.hInstance, (UINT)((ULONG_PTR)pszItem), pszBuffer, ccBuffer) == 0) { LoadString(::hModule, IDS_SPECIAL, pszBuffer, ccBuffer); } pszItem = pszBuffer; }
TraceLeaveValue(pszItem); }
int CAdvancedListPage::AddAce(HWND hListView, PACE_HEADER pAceHeader, int iRow, LPCTSTR pszInheritSource, int level) { PACE pAce = new CAce(pAceHeader); if (pAce) { iRow = AddAce(hListView, pAce, iRow,pszInheritSource, level); } return iRow; }
int CAdvancedListPage::AddAce(HWND hListView, PACE pAceNew, int iRow,LPCTSTR pszInheritSource, int level) { PACE pAceCompare; TCHAR szBuffer[MAX_COLUMN_CHARS]; LPCTSTR pszInheritType; LPCTSTR pszRights; LV_ITEM lvi; UINT id = IDS_UNKNOWN; int iItem; int cItems;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::AddAce"); TraceAssert(hListView != NULL); TraceAssert(!m_bAbortPage);
if (pAceNew == NULL) TraceLeaveValue(-1);
pAceNew->SetInheritSourceInfo(pszInheritSource, level); m_psi->MapGeneric(&pAceNew->ObjectType, &pAceNew->AceFlags, &pAceNew->Mask);
//
// Try to merge the new ACE with an existing entry in the list.
//
cItems = ListView_GetItemCount(hListView); lvi.iSubItem = 0; lvi.mask = LVIF_PARAM;
while (cItems > 0) { --cItems; lvi.iItem = cItems;
ListView_GetItem(hListView, &lvi); pAceCompare = (PACE)lvi.lParam;
if (pAceCompare != NULL) { switch (pAceNew->Merge(pAceCompare)) { case MERGE_MODIFIED_FLAGS: case MERGE_MODIFIED_MASK: // The ACEs were merged into pAceNew.
case MERGE_OK_1: //
// The new ACE implies the existing ACE, so the existing
// ACE can be removed.
//
// First copy the name so we don't have to look
// it up again. (Don't copy the other strings
// since they may be different.)
//
// Then keep looking. Maybe we can remove some more entries
// before adding the new one.
//
if (pAceNew->GetName() == NULL) pAceNew->SetName(pAceCompare->GetName()); ListView_DeleteItem(hListView, cItems); iRow = cItems; // try to insert here
break;
case MERGE_OK_2: //
// The existing ACE implies the new ACE, so we don't
// need to do anything here.
//
delete pAceNew; TraceLeaveValue(cItems); break; } } }
//
// Make sure we have a name for the SID.
//
pAceNew->LookupName(m_siObjectInfo.pszServerName, m_psi2);
//
// Get the Access Type and Inherit Type strings
//
pszRights = TranslateAceIntoRights(pAceNew->AceFlags, pAceNew->Mask, &pAceNew->ObjectType, &pAceNew->InheritedObjectType, &pszInheritType);
//
// If this is a property ACE, give it a name like "Read property" or
// "Write property". Also, remember that it's a property ACE so we
// can show the Property page first when editing this ACE.
//
// This is a bit slimy, since it assumes DS property access bits are
// the only ones that will ever be used on the properties page.
//
if ((m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES) && (pAceNew->Flags & ACE_OBJECT_TYPE_PRESENT) && (pAceNew->Mask & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP)) && !(pAceNew->Mask & ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP))) { pAceNew->SetPropertyAce(TRUE);
if (pszRights == NULL) { UINT idString = 0;
switch (pAceNew->Mask & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP)) { case ACTRL_DS_READ_PROP: idString = IDS_READ_PROP; break;
case ACTRL_DS_WRITE_PROP: idString = IDS_WRITE_PROP; break;
case (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP): idString = IDS_READ_WRITE_PROP; break; }
if (idString) { LoadString(::hModule, idString, szBuffer, ARRAYSIZE(szBuffer)); pszRights = szBuffer; } } }
pszRights = GetItemString(pszRights, szBuffer, ARRAYSIZE(szBuffer)); pAceNew->SetAccessType(pszRights);
if (m_siObjectInfo.dwFlags & SI_CONTAINER) { pszInheritType = GetItemString(pszInheritType, szBuffer, ARRAYSIZE(szBuffer)); pAceNew->SetInheritType(pszInheritType); }
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; lvi.state = 0; lvi.stateMask = LVIS_CUT; lvi.iItem = iRow; lvi.iSubItem = 0; lvi.pszText = LPSTR_TEXTCALLBACK; lvi.lParam = (LPARAM)pAceNew;
if (pAceNew->AceFlags & INHERITED_ACE) { #ifdef USE_OVERLAY_IMAGE
lvi.state = LVIS_CUT | INDEXTOOVERLAYMASK(1); #else
lvi.state = LVIS_CUT; #endif
}
//
// Get the string ID for the Type column
//
if (m_siPageType == SI_PAGE_ADVPERM) { switch(pAceNew->AceType) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_ALLOWED_OBJECT_ACE_TYPE: id = IDS_ALLOW; break;
case ACCESS_DENIED_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: id = IDS_DENY; break;
case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: id = IDS_AUDIT; break;
case SYSTEM_ALARM_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: id = IDS_ALARM; break; } } else {
switch(pAceNew->AceFlags & (SUCCESSFUL_ACCESS_ACE_FLAG|FAILED_ACCESS_ACE_FLAG)) { case SUCCESSFUL_ACCESS_ACE_FLAG: id = IDS_AUDITPASS; break;
case FAILED_ACCESS_ACE_FLAG: id = IDS_AUDITFAIL; break;
case SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG: id = IDS_AUDITBOTH; break; } }
// Load the Type string
LoadString(::hModule, id, szBuffer, ARRAYSIZE(szBuffer)); pAceNew->SetType(szBuffer);
//
// Finally, insert the item into the list
//
iItem = ListView_InsertItem(hListView, &lvi);
if (iItem == -1) delete pAceNew;
TraceLeaveValue(iItem); }
void CAdvancedListPage::UpdateButtons( HWND hDlg ) { HWND hListView; BOOL fEnableButtons = FALSE; LVITEM lvi = {0}; UINT cSelectedCount = 0; //Number of item selected in listbox
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::UpdateButtons");
hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS); cSelectedCount = ListView_GetSelectedCount(hListView);
if (!m_bAbortPage) { //If SelectedCount > 1, disable View\Edit button
if( cSelectedCount <= 1 ) { lvi.iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
// Decide whether or not to enable edit button and decide what description
// to display for the ACE
if (lvi.iItem != -1) fEnableButtons = TRUE; }
HWND hwndEdit = GetDlgItem(hDlg, IDC_ACEL_EDIT);
// If we're disabling the edit button, make sure it doesn't have
// focus or keyboard access gets hosed.
if (!fEnableButtons && GetFocus() == hwndEdit) SetFocus(hListView);
EnableWindow(hwndEdit, fEnableButtons); }
if (m_bReadOnly) { const int idDisable[] = { IDC_ACEL_ADD, IDC_ACEL_REMOVE, IDC_ACEL_RESET, IDC_ACEL_PROTECT, IDC_ACEL_RESET_ACL_TREE, }; for (int i = 0; i < ARRAYSIZE(idDisable); i++) EnableWindow(GetDlgItem(hDlg, idDisable[i]), FALSE); } else { // The Remove button is enabled if any selected ace is direct
if ( AnySelectedAceofType( hListView, TRUE ) ) fEnableButtons = TRUE; else fEnableButtons = FALSE;
HWND hwndRemove = GetDlgItem(hDlg, IDC_ACEL_REMOVE);
// If we're disabling the remove button, make sure it doesn't have
// focus or keyboard access gets hosed.
if (!fEnableButtons && GetFocus() == hwndRemove) SetFocus(hListView);
EnableWindow(hwndRemove, fEnableButtons); }
TraceLeaveVoid(); }
PACL CAdvancedListPage::GetACL(PSECURITY_DESCRIPTOR *ppSD, LPBOOL pbProtected, BOOL bDefault) { PACL pAcl = NULL; SECURITY_DESCRIPTOR_CONTROL sdControl = 0; DWORD dwRevision; BOOL bPresent; HRESULT hr;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::GetACL"); TraceAssert(ppSD != NULL); TraceAssert(pbProtected != NULL); TraceAssert(m_psi != NULL); TraceAssert(!m_bAbortPage);
*pbProtected = FALSE;
if (m_siPageType == SI_PAGE_ADVPERM) { hr = m_psi->GetSecurity(DACL_SECURITY_INFORMATION, ppSD, bDefault);
if (SUCCEEDED(hr) && *ppSD != NULL) { GetSecurityDescriptorControl(*ppSD, &sdControl, &dwRevision); *pbProtected = ((sdControl & SE_DACL_PROTECTED) != 0); GetSecurityDescriptorDacl(*ppSD, &bPresent, &pAcl, &bDefault); } } else { DWORD dwPriv = SE_SECURITY_PRIVILEGE; HANDLE hToken = EnablePrivileges(&dwPriv, 1);
hr = m_psi->GetSecurity(SACL_SECURITY_INFORMATION, ppSD, bDefault);
ReleasePrivileges(hToken);
if (SUCCEEDED(hr)) { if (*ppSD != NULL) { GetSecurityDescriptorControl(*ppSD, &sdControl, &dwRevision); *pbProtected = ((sdControl & SE_SACL_PROTECTED) != 0); GetSecurityDescriptorSacl(*ppSD, &bPresent, &pAcl, &bDefault); } } else { // If we can't read the SACL, we can't write it either
m_bReadOnly = TRUE; } }
//Get the count of inheritable aces
m_cInheritableAces = GetCountOfInheritableAces(pAcl);
TraceLeaveValue(pAcl); }
void CAdvancedListPage::FillAceList(HWND hListView, PACL pAcl, BOOL bSortList) { TraceEnter(TRACE_ACELIST, "CAdvancedListPage::FillAceList"); TraceAssert(!m_bAbortPage); //
// Enumerate the ACL into the ListView
//
// Turn off redraw and empty out the list
SendMessage(hListView, WM_SETREDRAW, FALSE, 0); ListView_DeleteAllItems(hListView);
if (pAcl) { PACE_HEADER pAceHeader; UINT AceCount; int iRow = 0; HRESULT hr = S_OK; SECURITY_INFORMATION si = (m_siPageType == SI_PAGE_ADVPERM) ? DACL_SECURITY_INFORMATION :SACL_SECURITY_INFORMATION; PINHERITED_FROM pInheritArray = NULL; if(m_psoti) { DWORD dwPriv = SE_SECURITY_PRIVILEGE; HANDLE hToken = EnablePrivileges(&dwPriv, 1); hr = m_psoti->GetInheritSource(si, pAcl, &pInheritArray); ReleasePrivileges(hToken); } //
// Enumerate all of the ACEs, putting the data into the list view
//
ULONG i = 0; for (AceCount = pAcl->AceCount, pAceHeader = (PACE_HEADER)FirstAce(pAcl); AceCount > 0; AceCount--, pAceHeader = (PACE_HEADER)NextAce(pAceHeader), ++i) { iRow = AddAce(hListView, pAceHeader, iRow, pInheritArray? pInheritArray[i].AncestorName : NULL, pInheritArray? pInheritArray[i].GenerationGap :0 ) + 1; } LocalFree(pInheritArray); }
if (bSortList) { //
// Sort the list,if no column is clicked so far,
// sort in the cannonical order else in the last column clicked order
//
if(m_iLastColumnClick == -1) { ListView_SortItems(hListView, AceListCompareProcCanno, MAKELPARAM(0, 1)); } else { ListView_SortItems(hListView, AceListCompareProc, MAKELPARAM(m_iLastColumnClick, m_iSortDirection)); } }
//
// Now select the first item
//
SelectListViewItem(hListView, 0);
// Redraw the list
SendMessage(hListView, WM_SETREDRAW, TRUE, 0); ListView_RedrawItems(hListView, 0, -1);
TraceLeaveVoid(); }
COL_FOR_LV perm_col_for_container[] = { IDS_ACE_PERM_COLUMN_TYPE, 10, IDS_ACE_PERM_COLUMN_NAME, 25, IDS_ACE_PERM_COLUMN_ACCESS, 20, IDS_ACE_PERM_COLUMN_PARENT, 20, IDS_ACE_PERM_COLUMN_INHERIT, 25, };
COL_FOR_LV perm_col_for_noncontainer[] = { IDS_ACE_PERM_COLUMN_TYPE, 10, IDS_ACE_PERM_COLUMN_NAME, 35, IDS_ACE_PERM_COLUMN_ACCESS, 20, IDS_ACE_PERM_COLUMN_PARENT, 35, };
COL_FOR_LV audit_col_for_container[] = { IDS_ACE_AUDIT_COLUMN_TYPE, 13, IDS_ACE_AUDIT_COLUMN_NAME, 25, IDS_ACE_AUDIT_COLUMN_ACCESS, 20, IDS_ACE_PERM_COLUMN_PARENT, 20, IDS_ACE_AUDIT_COLUMN_INHERIT, 25, };
COL_FOR_LV audit_col_for_noncontainer[] = { IDS_ACE_AUDIT_COLUMN_TYPE, 10, IDS_ACE_AUDIT_COLUMN_NAME, 35, IDS_ACE_AUDIT_COLUMN_ACCESS, 20, IDS_ACE_PERM_COLUMN_PARENT, 35, };
void CAdvancedListPage::InitDlg( HWND hDlg ) { HWND hListView; RECT rc; TCHAR szBuffer[MAX_COLUMN_CHARS]; LV_COLUMN col; UINT iTotal = 0; HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::InitDlg");
// Hide the Reset button if it isn't supported.
if (!(m_siObjectInfo.dwFlags & SI_RESET) && !((m_siPageType == SI_PAGE_ADVPERM) && (m_siObjectInfo.dwFlags & SI_RESET_DACL)) && !((m_siPageType == SI_PAGE_AUDIT) && (m_siObjectInfo.dwFlags & SI_RESET_SACL)) ) { HWND hwnd = GetDlgItem(hDlg, IDC_ACEL_RESET); ShowWindow(hwnd, SW_HIDE); EnableWindow(hwnd, FALSE); hwnd = GetDlgItem(hDlg, IDC_ACEL_DEFAULT_STATIC); ShowWindow(hwnd, SW_HIDE); EnableWindow(hwnd, FALSE); }
if (m_siObjectInfo.dwFlags & SI_NO_ACL_PROTECT) { // Hide the "Inherit permissions" box
HWND hwnd = GetDlgItem(hDlg, IDC_ACEL_PROTECT); ShowWindow(hwnd, SW_HIDE); EnableWindow(hwnd, FALSE); }
if (!(m_siObjectInfo.dwFlags & SI_CONTAINER) || !(m_siObjectInfo.dwFlags & (m_siPageType == SI_PAGE_ADVPERM ? SI_RESET_DACL_TREE : SI_RESET_SACL_TREE))) { // Hide the "Reset ACL" box
HWND hwnd = GetDlgItem(hDlg, IDC_ACEL_RESET_ACL_TREE); ShowWindow(hwnd, SW_HIDE); EnableWindow(hwnd, FALSE); }
if (m_siPageType == SI_PAGE_ADVPERM) { m_bReadOnly = !!(m_siObjectInfo.dwFlags & SI_READONLY); }
//If readonly, change edit button to view
if(m_bReadOnly) { LoadString(::hModule, IDS_VIEW, szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(hDlg,IDC_ACEL_EDIT,szBuffer); LoadString(::hModule, (m_siPageType == SI_PAGE_ADVPERM)?IDS_ACL_EDIT_MORE_INFO:IDS_ACL_EDIT_MORE_INFO_1, szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(hDlg,IDC_ACEL_STATIC,szBuffer); }
hListView = GetDlgItem( hDlg, IDC_ACEL_DETAILS );
if (m_bAbortPage) { //
// Disable everything
//
m_bReadOnly = TRUE; EnableWindow(hListView, FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ACEL_EDIT), FALSE); } else { //
// Get the ACL
//
PSECURITY_DESCRIPTOR pSD = NULL; BOOL fProtected = FALSE; PACL pAcl = GetACL(&pSD, &fProtected, FALSE);
if (m_siPageType == SI_PAGE_AUDIT) { if (pAcl && pAcl->AceCount) { // Audits are already in place, don't bother checking
// whether auditing is enabled later.
m_bAuditPolicyOK = TRUE; }
//Check if any of the ace in SACL is Callback type
//if yes hide all the controls and show the error
//message.
if(IsCallBackAcePresentInAcl(pAcl)) { HWND hwnd; for (hwnd = GetWindow(hDlg, GW_CHILD); hwnd != NULL; hwnd = GetWindow(hwnd, GW_HWNDNEXT)) { ShowWindow(hwnd, SW_HIDE); EnableWindow(hwnd, FALSE); } // Enable and show the "No Security" message
hwnd = GetDlgItem(hDlg, IDC_SPP_CALLBACK_PERMISSIONS); EnableWindow(hwnd, TRUE); ShowWindow(hwnd, SW_SHOW); if (pSD) LocalFree(pSD); // We're done with it, now free it
return; } } else { DWORD dwFullControl = GENERIC_ALL; UCHAR aceFlags = 0;
m_psi->MapGeneric(NULL, &aceFlags, &dwFullControl); if (IsDenyACL(pAcl, fProtected, dwFullControl, NULL)) { // Already have Deny ACEs, don't bother warning again later.
m_bWasDenyAcl = TRUE; } }
//
// Set up the listview control
//
// Set extended LV style for whole line selection with InfoTips
ListView_SetExtendedListViewStyleEx(hListView, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
//
// Add appropriate columns
//
GetClientRect(hListView, &rc); if (pAcl && pAcl->AceCount > 10) rc.right -= GetSystemMetrics(SM_CYHSCROLL); // Make room for scrollbar
COL_FOR_LV *cfl; UINT iColCount;
if (m_siObjectInfo.dwFlags & SI_CONTAINER) { // Get the inherit types for filling in the inherit column
m_cInheritTypes = 0; m_pInheritType = NULL; m_psi->GetInheritTypes(&m_pInheritType, &m_cInheritTypes);
cfl = perm_col_for_container; iColCount = ARRAYSIZE(perm_col_for_container);
if (m_siPageType == SI_PAGE_AUDIT) { cfl = audit_col_for_container; iColCount = ARRAYSIZE(audit_col_for_container); } } else { // There is no inherit column for non-containers
cfl = perm_col_for_noncontainer; iColCount = ARRAYSIZE(perm_col_for_noncontainer);
if (m_siPageType == SI_PAGE_AUDIT) { cfl = audit_col_for_noncontainer; iColCount = ARRAYSIZE(audit_col_for_noncontainer); } }
UINT iCol;
iCol = 0; while (iCol < iColCount) { LoadString(::hModule, cfl[iCol].idText, szBuffer, ARRAYSIZE(szBuffer)); col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; col.fmt = LVCFMT_LEFT; col.pszText = szBuffer; col.iSubItem = iCol;
if (iCol == iColCount - 1) col.cx = rc.right - iTotal; else col.cx = (rc.right * cfl[iCol].iPercent) / 100;
ListView_InsertColumn(hListView, iCol, &col); iTotal += col.cx; iCol++; }
//
// Get the access list for filling in the Rights column
//
ULONG iDefaultAccess; DWORD dwFlags = SI_ADVANCED; if (m_siPageType == SI_PAGE_AUDIT) dwFlags |= SI_EDIT_AUDITS; m_psi->GetAccessRights(NULL, dwFlags, &m_pAccess, &m_cAccesses, &iDefaultAccess);
//
// Enumerate the ACL into the ListView
//
FillAceList(hListView, pAcl, FALSE);
// Set the protection checkbox
CheckDlgButton(hDlg, IDC_ACEL_PROTECT, !fProtected);
if (pSD) LocalFree(pSD); // We're done with it, now free it
} // !m_bAbortPage
// Update the other controls
UpdateButtons(hDlg);
SetCursor(hcur);
TraceLeaveVoid(); }
//NTRAID#NTBUG9-555470-2002/03/29-hiteshr
HRESULT CAdvancedListPage::BuildAcl(HWND hListView, PACL *ppAcl) { long cAces; long iEntry; long iLength = SIZEOF(ACL); PACE pAce; PACL pACL = NULL; LV_ITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; lvi.lParam = NULL;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::BuildAcl"); TraceAssert(hListView != NULL); TraceAssert(ppAcl != NULL);
*ppAcl = NULL;
cAces = ListView_GetItemCount(hListView);
//
// Iterate through all of the ace's counting up size.
// If there are no ACEs, create an empty ACL.
//
for (iEntry = 0; iEntry < cAces; iEntry++) { lvi.iItem = iEntry; ListView_GetItem(hListView, &lvi);
pAce = (PACE)lvi.lParam; if (pAce) { if (!(pAce->AceFlags & INHERITED_ACE)) iLength += pAce->AceSize; } }
pACL = (PACL)LocalAlloc(LPTR, iLength); if (pACL) { PACE_HEADER pAceDest;
InitializeAcl(pACL, iLength, ACL_REVISION);
for (iEntry = 0, pAceDest = (PACE_HEADER)FirstAce(pACL); iEntry < cAces; iEntry++) { lvi.iItem = iEntry; ListView_GetItem(hListView, &lvi);
pAce = (PACE)lvi.lParam; if (pAce) { if (!(pAce->AceFlags & INHERITED_ACE)) { //Remveod the special casing for CREATOR_OWNER
//NTRAID#NTBUG9-467049-2001/11/29-hiteshr
pAce->CopyTo(pAceDest); pACL->AceCount++; pAceDest = (PACE_HEADER)NextAce(pAceDest);
// Is this an object ACE? If so, reset the ACL revision.
if (pAce->Flags != 0 && pACL->AclRevision < ACL_REVISION_DS) pACL->AclRevision = ACL_REVISION_DS; } } }
iLength = (ULONG)((PBYTE)pAceDest - (PBYTE)pACL); TraceAssert(pACL->AclSize >= iLength);
if (pACL->AclSize > iLength) pACL->AclSize = (WORD)iLength;
TraceAssert(IsValidAcl(pACL)); } else { TraceLeaveResult(E_OUTOFMEMORY); }
*ppAcl = pACL;
TraceLeaveResult(S_OK); }
HRESULT CAdvancedListPage::ApplyPermissions(HWND hDlg, HWND hListView, BOOL fProtected) { HRESULT hr = S_OK; PACL pACL = NULL; SECURITY_DESCRIPTOR sd; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; BOOL bIsDenyAcl = FALSE;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::ApplyPermissions"); TraceAssert(hDlg != NULL); TraceAssert(hListView != NULL); TraceAssert(!m_bReadOnly); TraceAssert(!m_bAbortPage);
if (IsDlgButtonChecked(hDlg, IDC_ACEL_RESET_ACL_TREE)) { // Confirm this operation
if (IDNO == MsgPopup(hDlg, MAKEINTRESOURCE(IDS_RESET_DACL_WARNING), MAKEINTRESOURCE(IDS_SECURITY), MB_YESNO | MB_ICONWARNING, ::hModule, m_siObjectInfo.pszObjectName)) { // Return PSNRET_INVALID to abort the Apply and tell the sheet to
// select this page as the active page.
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); ExitGracefully(hr, S_OK, "ApplyPermissions aborting"); }
si |= SI_RESET_DACL_TREE; }
// Make sure the DACL is in canonical order. Note that OnApply
// will re-read the DACL and reinitialize the list with the
// current sort order.
ListView_SortItems(hListView, AceListCompareProcCanno, MAKELPARAM(0, 1));
// Build the new DACL
//NTRAID#NTBUG9-555470-2002/03/29-hiteshr
hr = BuildAcl(hListView, &pACL); if(FAILED(hr)) TraceLeaveResult(hr);
// Check for Deny ACEs in the ACL
if (!m_bWasDenyAcl) { DWORD dwWarning = 0; DWORD dwFullControl = GENERIC_ALL; UCHAR aceFlags = 0;
m_psi->MapGeneric(NULL, &aceFlags, &dwFullControl); bIsDenyAcl = IsDenyACL(pACL, fProtected, dwFullControl, &dwWarning); if (bIsDenyAcl) { TraceAssert(dwWarning != 0);
// Warn the user about Deny ACEs
if (IDNO == MsgPopup(hDlg, MAKEINTRESOURCE(dwWarning), MAKEINTRESOURCE(IDS_SECURITY), MB_YESNO | MB_ICONWARNING, ::hModule, m_siObjectInfo.pszObjectName)) { // Return PSNRET_INVALID to abort the Apply and tell the sheet to
// select this page as the active page.
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); ExitGracefully(hr, S_OK, "ApplyPermissions aborting"); } } }
// Build the security descriptor
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"InitializeSecurityDescriptor failed"); }
if(!SetSecurityDescriptorDacl(&sd, !!(pACL), pACL, FALSE)) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorDacl failed"); }
sd.Control |= SE_DACL_AUTO_INHERIT_REQ;
if (fProtected) sd.Control |= SE_DACL_PROTECTED;
if(IsAclBloated(hDlg, si, &sd, m_cInheritableAces,m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES)) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); ExitGracefully(hr, S_FALSE, "ApplyPermissions aborting"); } // Write out the new DACL
hr = m_psi->SetSecurity(si, &sd);
if (bIsDenyAcl && S_OK == hr) m_bWasDenyAcl = TRUE;
exit_gracefully:
if (pACL) LocalFree(pACL);
TraceLeaveResult(hr); }
HRESULT CAdvancedListPage::ApplyAudits(HWND hDlg, HWND hListView, BOOL fProtected) { HRESULT hr = S_OK; PACL pACL = NULL; SECURITY_DESCRIPTOR sd; SECURITY_INFORMATION si = SACL_SECURITY_INFORMATION; DWORD dwPriv = SE_SECURITY_PRIVILEGE; HANDLE hToken = INVALID_HANDLE_VALUE;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::ApplyAudits"); TraceAssert(!m_bReadOnly); TraceAssert(!m_bAbortPage);
if (IsDlgButtonChecked(hDlg, IDC_ACEL_RESET_ACL_TREE)) si |= SI_RESET_SACL_TREE;
// Build the SACL
//NTRAID#NTBUG9-555470-2002/03/29-hiteshr
hr = BuildAcl(hListView, &pACL); if(FAILED(hr)) TraceLeaveResult(hr);
// Build the security descriptor
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"InitializeSecurityDescriptor failed"); }
if(!SetSecurityDescriptorSacl(&sd, !!(pACL), pACL, FALSE)) { DWORD dwErr = GetLastError(); ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorSacl failed"); } sd.Control |= SE_SACL_AUTO_INHERIT_REQ;
if (fProtected) sd.Control |= SE_SACL_PROTECTED;
// Enable the security privilege and write out the new SACL
hToken = EnablePrivileges(&dwPriv, 1);
if(IsAclBloated(hDlg, si, &sd, m_cInheritableAces,m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES)) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); hr = S_FALSE; } else hr = m_psi->SetSecurity(si, &sd);
ReleasePrivileges(hToken);
if (S_OK == hr) CheckAuditPolicy(hDlg);
exit_gracefully:
if (pACL) LocalFree(pACL);
TraceLeaveResult(hr); }
void CAdvancedListPage::OnApply(HWND hDlg, BOOL bClose) { HRESULT hr = S_OK; HWND hListView; BOOL fProtected;
if (!m_fPageDirty) return;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::OnApply"); TraceAssert(hDlg != NULL); TraceAssert(!m_bReadOnly); TraceAssert(!m_bAbortPage);
hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS); fProtected = !IsDlgButtonChecked(hDlg, IDC_ACEL_PROTECT);
if (m_siPageType == SI_PAGE_ADVPERM) { hr = ApplyPermissions(hDlg, hListView, fProtected); } else { hr = ApplyAudits(hDlg, hListView, fProtected); }
if (FAILED(hr)) { // Tell the user there was a problem. If they choose to cancel
// and the dialog is closing, do nothing (let the dialog close).
// Otherwise, tell the property sheet that we had a problem.
UINT nMsgID = IDS_PERM_WRITE_FAILED; if (m_siPageType == SI_PAGE_AUDIT) nMsgID = IDS_AUDIT_WRITE_FAILED;
if (IDCANCEL != SysMsgPopup(hDlg, MAKEINTRESOURCE(nMsgID), MAKEINTRESOURCE(IDS_SECURITY), (bClose ? MB_RETRYCANCEL : MB_OK) | MB_ICONERROR, ::hModule, hr, m_siObjectInfo.pszObjectName)) { // Return PSNRET_INVALID to abort the Apply and cause the sheet to
// select this page as the active page.
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); } } else if (S_FALSE == hr) { // S_FALSE is silent failure (the client should put up UI
// during SetSecurity before returning S_FALSE).
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); } else { m_fPageDirty = FALSE;
// If ApplyPermissions bailed due to user action ("No"),
// then the dialog won't be closing
if (PSNRET_INVALID == GetWindowLongPtr(hDlg, DWLP_MSGRESULT)) bClose = FALSE;
if (!bClose) { //
// Re-read the security descriptor and reinitialize the dialog
//
//Inform the Effective Permission tab that
//Permissions are changed
if(m_siPageType == SI_PAGE_ADVPERM) PropSheet_QuerySiblings(GetParent(hDlg),0,0);
PSECURITY_DESCRIPTOR pSD = NULL; BOOL fACLProtected = FALSE; PACL pAcl = GetACL(&pSD, &fACLProtected, FALSE); FillAceList(hListView, pAcl);
// Set the button states
CheckDlgButton(hDlg, IDC_ACEL_PROTECT, !fACLProtected); CheckDlgButton(hDlg, IDC_ACEL_RESET_ACL_TREE, BST_UNCHECKED); UpdateButtons(hDlg);
if (pSD) LocalFree(pSD); // We're done with it, now free it
} }
TraceLeaveVoid(); }
void CAdvancedListPage::OnAdd(HWND hDlg) { PUSER_LIST pUserList = NULL;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::OnAdd"); TraceAssert(!m_bReadOnly);
if (S_OK == GetUserGroup(hDlg, FALSE, &pUserList)) { // Build an empty ACE (mask = 0) using the SID we just
// got in pUserList.
CAce ace;
TraceAssert(NULL != pUserList); TraceAssert(1 == pUserList->cUsers);
if (m_siPageType == SI_PAGE_AUDIT) ace.AceType = SYSTEM_AUDIT_ACE_TYPE;
if (m_siObjectInfo.dwFlags & SI_CONTAINER) ace.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
ace.SetSid(pUserList->rgUsers[0].pSid, pUserList->rgUsers[0].pszName, pUserList->rgUsers[0].pszLogonName, pUserList->rgUsers[0].SidType);
// Done with this now
LocalFree(pUserList);
// Edit the ACE
EditAce(hDlg, &ace, FALSE); }
TraceLeaveVoid(); }
BOOL CanDeleteDirectAces( HWND hDlg ) { TCHAR szBuffer[1024]; TCHAR szCaption[1024]; if( !LoadString( ::hModule, IDS_CONFIRM_MULTIPLE_DELETION, szBuffer, 1024 ) ) return FALSE; if( !LoadString( ::hModule, IDS_SECURITY, szCaption, 1024 ) ) return FALSE;
return (IDYES == MessageBox( hDlg, szBuffer, szCaption, MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL )); } void CAdvancedListPage::OnRemove(HWND hDlg) {
HWND hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS);
//if Any selected Ace is inherited from parent
//Ask user if to proceed with deletion of direct aces
if( AnySelectedAceofType(hListView, FALSE) && !CanDeleteDirectAces( hDlg ) ) return;
//Remember the positon of first selected permissons
//In end select the item at this position
int iFirstSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); LVITEM lvi = {0}; lvi.iItem = iFirstSelected; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; while( lvi.iItem != -1 ) {
lvi.lParam = NULL; ListView_GetItem(hListView, &lvi); if( (((PACE)lvi.lParam)->AceFlags & INHERITED_ACE) == 0 ) { ListView_DeleteItem(hListView, lvi.iItem); //Start from one item back as current item is deleted
--lvi.iItem; } lvi.iItem = ListView_GetNextItem(hListView, lvi.iItem, LVNI_SELECTED); }
if (ListView_GetItemCount(hListView) <= iFirstSelected ) --iFirstSelected;
SelectListViewItem(hListView, iFirstSelected);
PropSheet_Changed(GetParent(hDlg),hDlg); m_fPageDirty = TRUE; }
void CAdvancedListPage::OnReset(HWND hDlg) { //
// Get a default ACL and enumerate it into the ListView
//
PSECURITY_DESCRIPTOR pSD = NULL; BOOL fProtected = FALSE;
FillAceList(GetDlgItem(hDlg, IDC_ACEL_DETAILS), GetACL(&pSD, &fProtected, TRUE /*default*/));
// Set the button states
CheckDlgButton(hDlg, IDC_ACEL_PROTECT, !fProtected); UpdateButtons(hDlg);
if (pSD) LocalFree(pSD); // We're done with it, now free it
// Notify the property sheet that we've changed
PropSheet_Changed(GetParent(hDlg),hDlg); m_fPageDirty = TRUE; }
void CAdvancedListPage::OnProtect(HWND hDlg) { // The "Inherit permissions" checkbox was clicked
if (!IsDlgButtonChecked(hDlg, IDC_ACEL_PROTECT)) { BOOL bHaveInheritedAces = FALSE; HWND hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS); int cItems = ListView_GetItemCount(hListView); int i; PACE pAce; LV_ITEM lvItem; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM;
// Are there any inherited aces?
for (i = 0; i < cItems && !bHaveInheritedAces; i++) { lvItem.iItem = i; ListView_GetItem(hListView, &lvItem); pAce = (PACE)lvItem.lParam; if (pAce) bHaveInheritedAces = (pAce->AceFlags & INHERITED_ACE); }
if (bHaveInheritedAces) { int nResult; int iSelected;
// Turning protection on. Ask the user whether to convert
// inherited aces to non-inherited aces, or delete them.
nResult = ConfirmAclProtect(hDlg, m_siPageType == SI_PAGE_ADVPERM);
if (nResult == IDCANCEL) { // Reset the checkbox and bail
CheckDlgButton(hDlg, IDC_ACEL_PROTECT, BST_CHECKED); return; }
//
// Remember the current selection, if any.
//
iSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
//
// Convert or delete inherited aces
//
while (cItems > 0) { --cItems; lvItem.iItem = cItems;
//
// The AddAce call below merges entries, which
// can potentially remove entries from the list,
// so check the return value here. This also
// means we could see the same item more than
// once here, but after the first time it won't
// have the INHERITED_ACE flag set.
//
if (!ListView_GetItem(hListView, &lvItem)) continue;
pAce = (PACE)lvItem.lParam;
if (pAce && (pAce->AceFlags & INHERITED_ACE)) { if (nResult == IDC_CONFIRM_REMOVE) { // Delete it
ListView_DeleteItem(hListView, cItems); } else { //
// Convert it to non-inherited. Do this
// by deleting and re-adding without
// INHERITED_ACE set. AddAce will try
// to merge into existing entries.
//
// Before deleting, be sure to set
// lParam to zero so pAce doesn't
// get freed.
//
pAce->AceFlags &= ~INHERITED_ACE; lvItem.lParam = 0; ListView_SetItem(hListView, &lvItem); ListView_DeleteItem(hListView, cItems); AddAce(hListView, pAce, cItems, NULL,0); } } }
//
// Reset the selection
//
iSelected = min(ListView_GetItemCount(hListView)-1, iSelected); SelectListViewItem(hListView, iSelected); } }
PropSheet_Changed(GetParent(hDlg), hDlg); m_fPageDirty = TRUE; }
void CAdvancedListPage::OnEdit(HWND hDlg) { HWND hListView; PACE pAce; int iSelected;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::OnEdit"); TraceAssert(hDlg != NULL); TraceAssert(!m_bAbortPage);
hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS); pAce = (PACE)GetSelectedItemData(hListView, &iSelected); if(iSelected != -1) { EditAce(hDlg, pAce, TRUE, iSelected); }
TraceLeaveVoid(); }
int CAdvancedListPage::AddAcesFromDPA(HWND hListView, HDPA hEntries, int iSelected) { UINT iItems = 0;
if (hEntries) iItems = DPA_GetPtrCount(hEntries);
while (iItems) { --iItems; iSelected = AddAce(hListView, (PACE_HEADER)DPA_FastGetPtr(hEntries, iItems), iSelected, NULL,0) + 1; }
return iSelected; }
void CAdvancedListPage::EditAce(HWND hDlg, PACE pAce, BOOL bDeleteSelection, LONG iSelected) { HWND hListView; HDPA hEntries = NULL; HDPA hPropertyEntries = NULL; UINT iItems = 0; UINT iPropertyItems = 0; BOOL bUpdateList; UINT nStartPage = 0; DWORD dwResult = 0;
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::EditAce"); TraceAssert(hDlg != NULL); TraceAssert(!m_bAbortPage);
hListView = GetDlgItem(hDlg, IDC_ACEL_DETAILS);
if (pAce) { // If the ACE is inherited, don't delete it.
if (pAce->AceFlags & INHERITED_ACE) bDeleteSelection = FALSE;
// If this is a property ACE, we want to show the property page first.
if (pAce->IsPropertyAce()) { TraceAssert(m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES); nStartPage = 1; } }
bUpdateList = EditACEEntry(hDlg, m_psi, pAce, m_siPageType, m_siObjectInfo.pszObjectName, m_bReadOnly, &dwResult, &hEntries, (m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES) ? &hPropertyEntries : NULL, nStartPage) && !m_bReadOnly;
if (bUpdateList) { if (hEntries) iItems = DPA_GetPtrCount(hEntries);
if (hPropertyEntries) iPropertyItems = DPA_GetPtrCount(hPropertyEntries);
if (iItems + iPropertyItems) { if (bDeleteSelection) { if ((nStartPage == 0 && iItems != 0) || (nStartPage == 1 && iPropertyItems != 0)) { // The previous ace was modified, so delete it here.
ListView_DeleteItem(hListView, iSelected); } else if (iPropertyItems != 0 && !(pAce->Flags & ACE_OBJECT_TYPE_PRESENT) && (pAce->Mask & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP))) { //
// iPropertyItems != 0 implies nStartPage = 0 or else the
// "if" condition above would be true. nStartPage = 0
// implies iItems = 0 for the same reason. That means the
// ace has more in it that just property stuff (or it's a
// control access right), but the only changes occurred on the
// Property page. Make sure we get rid of any property bits
// in the original ace so that we don't incorrectly merge
// property changes into the original ace.
//
// An example of this:
// Suppose pAce->Mask == READ_CONTROL | ACTRL_DS_READ_PROP and
// no property GUID is present. Suppose the user edits the ace
// and clicks on the Property tab, then unchecks a bunch of
// things, including "Read all properties". The result
// "should be" a bunch of "Read <specific property>" aces.
// If we don't remove ACTRL_DS_READ_PROP from the original ace,
// then all of the "Read <specific property>" aces get merged
// back into the original ace for no net effect.
//
// The reverse situation (nStartPage = 1, iPropertyItems = 0,
// iItems != 0) is not a problem. In that case merging will
// occur correctly,
//
// Make a copy with everything except the property bits
if (pAce->Mask & ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP)) { EditAce_MakeCopyWithoutProperties: PACE_HEADER pAceHeader = pAce->Copy(); if (pAceHeader != NULL) { // Turn off property bits
((PKNOWN_ACE)pAceHeader)->Mask &= ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP); TraceAssert(((PKNOWN_ACE)pAceHeader)->Mask != 0); // 370573
// Add it to hPropertyEntries instead of hEntries,
// since hEntries can be NULL here but we know
// hPropertyEntries is non-NULL (iPropertyItems!=0)
DPA_AppendPtr(hPropertyEntries, pAceHeader); } } // Delete the old ace
ListView_DeleteItem(hListView, iSelected); } }
//
// Now merge the new aces into the existing list
//
iSelected = AddAcesFromDPA(hListView, hEntries, iSelected); iSelected = AddAcesFromDPA(hListView, hPropertyEntries, iSelected);
//
// Now select the last item inserted
//
SelectSingleItemInLV( hListView, iSelected -1 ); // Re-sort the list so the new and/or modified entries
// appear in the right place.
if(m_iLastColumnClick == -1) { ListView_SortItems(hListView, AceListCompareProcCanno, MAKELPARAM(0, 1)); } else { ListView_SortItems(hListView, AceListCompareProc, MAKELPARAM(m_iLastColumnClick, m_iSortDirection)); }
// After sorting, make sure the selection is visible.
EnsureListViewSelectionIsVisible(hListView); } else if (bDeleteSelection && dwResult) { // Everything succeeded, something was edited, but nothing was created
// (probably all boxes were unchecked). Delete the previous selection.
// 370573
// If the only change occurred on the Properties page, then we
// only want to turn off the property bits. We don't want to
// delete the whole thing.
if (EAE_NEW_PROPERTY_ACE == dwResult && (pAce->Mask & ~(ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP))) { if (!hPropertyEntries) hPropertyEntries = DPA_Create(1); if (hPropertyEntries) goto EditAce_MakeCopyWithoutProperties; }
// Delete the previous selection.
ListView_DeleteItem(hListView, iSelected); }
// Was anything edited?
if (dwResult) { PropSheet_Changed(GetParent(hDlg),hDlg); m_fPageDirty = TRUE; } }
if (hEntries) DestroyDPA(hEntries);
if (hPropertyEntries) DestroyDPA(hPropertyEntries);
TraceLeaveVoid(); }
void CAdvancedListPage::CheckAuditPolicy(HWND hwndOwner) { //
// Check whether auditing is turned on and warn the user if not.
//
TraceEnter(TRACE_ACELIST, "CAdvancedListPage::CheckAuditPolicy");
if (!m_bAuditPolicyOK) { LSA_HANDLE hPolicy = GetLSAConnection(m_siObjectInfo.pszServerName, POLICY_VIEW_AUDIT_INFORMATION);
if (hPolicy != NULL) { PPOLICY_AUDIT_EVENTS_INFO pAuditInfo = NULL;
LsaQueryInformationPolicy(hPolicy, PolicyAuditEventsInformation, (PVOID*)&pAuditInfo);
if (pAuditInfo != NULL) { // We don't need to do this work again
m_bAuditPolicyOK = TRUE;
if (!pAuditInfo->AuditingMode) { // Auditing is not on... warn the user
MsgPopup(hwndOwner, MAKEINTRESOURCE(IDS_AUDIT_OFF_WARNING), MAKEINTRESOURCE(IDS_SECURITY), MB_OK | MB_ICONWARNING, ::hModule); }
LsaFreeMemory(pAuditInfo); } else { TraceMsg("LsaQueryInformationPolicy failed"); }
LsaClose(hPolicy); } else { TraceMsg("Unable to open LSA policy handle"); } }
TraceLeaveVoid(); }
BOOL CAdvancedListPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { PACE pAce;
switch(uMsg) { case WM_INITDIALOG: InitDlg(hDlg); break;
case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; LPNM_LISTVIEW pnmlv = (LPNM_LISTVIEW)lParam;
// Set default return value
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
switch (pnmh->code) { case NM_DBLCLK: if (pnmh->idFrom == IDC_ACEL_DETAILS) OnEdit(hDlg); break;
case LVN_ITEMCHANGED: if (pnmlv->uChanged & LVIF_STATE) UpdateButtons(hDlg); break;
case LVN_DELETEITEM: pAce = (PACE)pnmlv->lParam; delete pAce; break;
case LVN_KEYDOWN: if (((LPNMLVKEYDOWN)pnmh)->wVKey == VK_DELETE) if( IsWindowEnabled( GetDlgItem( hDlg, IDC_ACEL_REMOVE ) ) ) SendMessage(hDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDC_ACEL_REMOVE, NULL, 0)); break;
#define lvi (((NMLVDISPINFO*)lParam)->item)
case LVN_GETDISPINFO: pAce = (PACE)lvi.lParam; if ((lvi.mask & LVIF_TEXT) && pAce) { switch (lvi.iSubItem) { case 0: lvi.pszText = pAce->GetType(); break;
case 1: lvi.pszText = pAce->GetName(); break;
case 2: lvi.pszText = pAce->GetAccessType(); break; case 3: lvi.pszText = pAce->GetInheritSourceName(); break; case 4: lvi.pszText = pAce->GetInheritType(); break; } } break; #undef lvi
case LVN_COLUMNCLICK: if (m_iLastColumnClick == pnmlv->iSubItem) m_iSortDirection = -m_iSortDirection; else m_iSortDirection = 1; m_iLastColumnClick = pnmlv->iSubItem; ListView_SortItems(pnmh->hwndFrom, AceListCompareProc, MAKELPARAM(m_iLastColumnClick, m_iSortDirection)); EnsureListViewSelectionIsVisible(pnmh->hwndFrom); break;
case PSN_APPLY: OnApply(hDlg, (BOOL)(((LPPSHNOTIFY)lParam)->lParam)); break; case NM_CLICK: case NM_RETURN: { if(wParam == IDC_EFF_STATIC) { if(m_siPageType == SI_PAGE_AUDIT) { HtmlHelp(hDlg, c_szAuditHelpLink, HH_DISPLAY_TOPIC, 0); } else { HtmlHelp(hDlg, c_szPermHelpLink, HH_DISPLAY_TOPIC, 0);
} } } break;
} } break;
case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ACEL_ADD: OnAdd(hDlg); break;
case IDC_ACEL_REMOVE: OnRemove(hDlg); break;
case IDC_ACEL_EDIT: OnEdit(hDlg); break;
case IDC_ACEL_RESET: OnReset(hDlg); break;
case IDC_ACEL_RESET_ACL_TREE: if (!m_fPageDirty) { PropSheet_Changed(GetParent(hDlg),hDlg); m_fPageDirty = TRUE; } break;
case IDC_ACEL_PROTECT: if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED && !m_bReadOnly) { OnProtect(hDlg); } break;
default: return FALSE; } break;
case WM_HELP: if (IsWindowEnabled(hDlg)) { const DWORD *pdwHelpIDs = aAceListPermHelpIDs;
if (m_siPageType == SI_PAGE_AUDIT) pdwHelpIDs = aAceListAuditHelpIDs;
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, c_szAcluiHelpFile, HELP_WM_HELP, (DWORD_PTR)pdwHelpIDs); } break;
case WM_CONTEXTMENU: if (IsWindowEnabled(hDlg)) { const DWORD *pdwHelpIDs = aAceListPermHelpIDs;
if (m_siPageType == SI_PAGE_AUDIT) pdwHelpIDs = aAceListAuditHelpIDs;
WinHelp(hDlg, c_szAcluiHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)pdwHelpIDs); } break;
default: return FALSE; }
return TRUE; }
HPROPSHEETPAGE CreateAdvPermissionPage( LPSECURITYINFO psi ) { HPROPSHEETPAGE hPage = NULL; PADVANCEDLISTPAGE pPage;
TraceEnter(TRACE_ACELIST, "CreateAdvPermissionPage");
pPage = new CAdvancedListPage( psi, SI_PAGE_ADVPERM );
if (pPage) { hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(IDD_ACELIST_PERM_PAGE));
if (!hPage) delete pPage; }
TraceLeaveValue(hPage); }
HPROPSHEETPAGE CreateAdvAuditPage( LPSECURITYINFO psi ) { HPROPSHEETPAGE hPage = NULL; PADVANCEDLISTPAGE pPage;
TraceEnter(TRACE_ACELIST, "CreateAdvAuditPage");
pPage = new CAdvancedListPage( psi, SI_PAGE_AUDIT );
if (pPage) { hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(IDD_ACELIST_AUDIT_PAGE));
if (!hPage) delete pPage; }
TraceLeaveValue(hPage); }
//
// Expose an api to get at the ace list editor
//
BOOL ACLUIAPI EditSecurityEx(HWND hwndOwner, LPSECURITYINFO psi, PPERMPAGE pPermPage, UINT nStartPage, BOOL &refbNoReadWriteCanWriteOwner) { HPROPSHEETPAGE hPage[4]; UINT cPages = 0; BOOL bResult = FALSE; SI_OBJECT_INFO siObjectInfo = {0}; HRESULT hr;
TraceEnter(TRACE_ACELIST, "EditSecurityEx");
// Get flags and object name information
hr = psi->GetObjectInformation(&siObjectInfo);
if (FAILED(hr)) { SysMsgPopup(hwndOwner, MAKEINTRESOURCE(IDS_OPERATION_FAILED), MAKEINTRESOURCE(IDS_SECURITY), MB_OK | MB_ICONERROR, ::hModule, hr); TraceLeaveValue(FALSE); }
hPage[cPages] = CreateAdvPermissionPage( psi ); if (hPage[cPages]) cPages++;
if (siObjectInfo.dwFlags & SI_EDIT_AUDITS) { hPage[cPages] = CreateAdvAuditPage( psi ); if (hPage[cPages]) cPages++; }
if (siObjectInfo.dwFlags & SI_EDIT_OWNER) { hPage[cPages] = CreateOwnerPage( psi, &siObjectInfo, refbNoReadWriteCanWriteOwner ); if (hPage[cPages]) cPages++; }
if((siObjectInfo.dwFlags & SI_EDIT_EFFECTIVE) && pPermPage->IsEffective()) { hPage[cPages] = CreateEffectivePermPage( psi, &siObjectInfo ); if (hPage[cPages]) { // pPermPage->SetEffectivePerm(hPage[cPages]);
cPages++; } }
if (cPages) { // Build dialog title string
LPTSTR pszCaption = NULL; FormatStringID(&pszCaption, ::hModule, IDS_ACEL_TITLE, siObjectInfo.pszObjectName);
PROPSHEETHEADER psh = {0}; psh.dwSize = SIZEOF(psh); psh.dwFlags = PSH_DEFAULT; psh.hwndParent = hwndOwner; psh.hInstance = ::hModule; psh.pszCaption = pszCaption; psh.nPages = cPages; psh.nStartPage = 0; psh.phpage = &hPage[0];
if (nStartPage < cPages) psh.nStartPage = nStartPage;
bResult = (BOOL)(PropertySheet(&psh) + 1);
LocalFreeString(&pszCaption); }
TraceLeaveValue(bResult); }
|