Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2379 lines
72 KiB

//+-------------------------------------------------------------------------
//
// 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);
}