//+------------------------------------------------------------------------- // // 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 //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 " aces. // If we don't remove ACTRL_DS_READ_PROP from the original ace, // then all of the "Read " 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); }