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.
1748 lines
54 KiB
1748 lines
54 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: aceedit.cpp
|
|
//
|
|
// This file contains the implementation for the advanced ACE editor
|
|
// page.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "aclpriv.h"
|
|
#include "sddl.h" // ConvertSidToStringSid
|
|
|
|
#define PWM_SELECT_PAGE (WM_APP - 1)
|
|
|
|
//
|
|
// Context Help IDs.
|
|
//
|
|
const static DWORD aAcePermHelpIDs[] =
|
|
{
|
|
IDC_ACEE_INHERITWARNING, IDH_NOHELP,
|
|
IDC_ACEE_NAME_STATIC, IDH_ACEE_PERM_NAME,
|
|
IDC_ACEE_NAME, IDH_ACEE_PERM_NAME,
|
|
IDC_ACEE_NAMEBUTTON, IDH_ACEE_PERM_NAMEBUTTON,
|
|
IDC_ACEE_APPLYONTO_STATIC, IDH_ACEE_PERM_INHERITTYPE,
|
|
IDC_ACEE_INHERITTYPE, IDH_ACEE_PERM_INHERITTYPE,
|
|
IDC_ACEE_ACCESS, IDH_ACEE_PERM_LIST,
|
|
IDC_ACEE_ALLOW, IDH_ACEE_PERM_LIST,
|
|
IDC_ACEE_DENY, IDH_ACEE_PERM_LIST,
|
|
IDC_ACEE_LIST, IDH_ACEE_PERM_LIST,
|
|
IDC_ACEE_INHERITIMMEDIATE, IDH_ACEE_PERM_INHERITIMMEDIATE,
|
|
IDC_ACEE_CLEAR, IDH_ACEE_PERM_CLEAR,
|
|
0, 0
|
|
};
|
|
const static DWORD aAceAuditHelpIDs[] =
|
|
{
|
|
IDC_ACEE_INHERITWARNING, IDH_NOHELP,
|
|
IDC_ACEE_NAME_STATIC, IDH_ACEE_AUDIT_NAME,
|
|
IDC_ACEE_NAME, IDH_ACEE_AUDIT_NAME,
|
|
IDC_ACEE_NAMEBUTTON, IDH_ACEE_AUDIT_NAMEBUTTON,
|
|
IDC_ACEE_APPLYONTO_STATIC, IDH_ACEE_AUDIT_INHERITTYPE,
|
|
IDC_ACEE_INHERITTYPE, IDH_ACEE_AUDIT_INHERITTYPE,
|
|
IDC_ACEE_ACCESS, IDH_ACEE_AUDIT_LIST,
|
|
IDC_ACEE_ALLOW, IDH_ACEE_AUDIT_LIST,
|
|
IDC_ACEE_DENY, IDH_ACEE_AUDIT_LIST,
|
|
IDC_ACEE_LIST, IDH_ACEE_AUDIT_LIST,
|
|
IDC_ACEE_INHERITIMMEDIATE, IDH_ACEE_AUDIT_INHERITIMMEDIATE,
|
|
IDC_ACEE_CLEAR, IDH_ACEE_AUDIT_CLEAR,
|
|
0, 0
|
|
};
|
|
|
|
|
|
class CACEPage : public CSecurityPage
|
|
{
|
|
private:
|
|
PACE m_pAce;
|
|
HDPA *m_phEntries;
|
|
PSID m_pSid;
|
|
DWORD m_siFlags;
|
|
DWORD *m_pdwResult;
|
|
GUID m_guidInheritType;
|
|
BOOL m_fInheritImmediateEnabled;
|
|
BOOL m_fPreviousImmediateSetting;
|
|
BOOL m_fReadOnly;
|
|
BOOL m_fPageDirty;
|
|
SI_INHERIT_TYPE m_siInheritUnknown;
|
|
CACEPage *m_pOtherPage;
|
|
HWND m_hwnd;
|
|
|
|
public:
|
|
CACEPage(LPSECURITYINFO psi,
|
|
SI_PAGE_TYPE siType,
|
|
PACE pAce,
|
|
BOOL bReadOnly,
|
|
DWORD dwFlags,
|
|
DWORD *pdwResult,
|
|
HDPA *phEntries);
|
|
virtual ~CACEPage();
|
|
|
|
private:
|
|
virtual BOOL DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// Prevent propsheet callbacks from reaching the object that invoked us
|
|
virtual UINT PSPageCallback(HWND, UINT, LPPROPSHEETPAGE) { return 1; }
|
|
|
|
void EmptyCheckList(HWND hwndList);
|
|
LONG CheckPermBoxes(HWND hwndList, PACE pAce, DWORD dwState);
|
|
LONG InitCheckList(HWND hDlg, PACE pAce);
|
|
LONG ReInitCheckList(HWND hDlg, HDPA hEntries);
|
|
VOID DisplayNoControlMessage(HWND hDlg, BOOL bDisplay);
|
|
void HideInheritedAceWarning(HWND hDlg);
|
|
void InitDlg(HWND hDlg);
|
|
BOOL OnChangeName(HWND hDlg);
|
|
BOOL OnClearAll(HWND hDlg);
|
|
void HandleSelChange(HWND hDlg, HWND hWnd);
|
|
LONG OnApply(HWND hDlg, BOOL bClose);
|
|
HWND m_hwndNoPerm;
|
|
BOOL IsAclBloated(HWND hDlg);
|
|
HDPA GetAceList(HWND hDlg);
|
|
};
|
|
typedef class CACEPage *LPACEPAGE;
|
|
|
|
CACEPage::CACEPage(LPSECURITYINFO psi,
|
|
SI_PAGE_TYPE siType,
|
|
PACE pAce,
|
|
BOOL bReadOnly,
|
|
DWORD dwFlags,
|
|
DWORD *pdwResult,
|
|
HDPA *phEntries)
|
|
: CSecurityPage(psi, siType), m_pAce(pAce), m_fReadOnly(bReadOnly),
|
|
m_siFlags(dwFlags), m_pdwResult(pdwResult), m_phEntries(phEntries),
|
|
m_hwndNoPerm(NULL),m_pOtherPage(NULL)
|
|
{
|
|
if (m_pdwResult)
|
|
*m_pdwResult = 0;
|
|
}
|
|
|
|
CACEPage::~CACEPage()
|
|
{
|
|
if (m_pSid)
|
|
LocalFree(m_pSid);
|
|
if(m_hwndNoPerm)
|
|
DestroyWindow(m_hwndNoPerm);
|
|
}
|
|
|
|
|
|
void
|
|
CACEPage::EmptyCheckList(HWND hwndList)
|
|
{
|
|
SendMessage(hwndList, CLM_RESETCONTENT, 0, 0);
|
|
}
|
|
|
|
|
|
LONG
|
|
CACEPage::CheckPermBoxes(HWND hwndList, PACE pAce, DWORD dwState)
|
|
{
|
|
LONG nLastChecked = -1;
|
|
UINT cItems;
|
|
BOOL bColumnAllow = FALSE;
|
|
BOOL bColumnDeny = FALSE;
|
|
|
|
//
|
|
// Check all boxes that correspond to a particular ACE
|
|
//
|
|
|
|
if (hwndList == NULL || pAce == NULL)
|
|
return -1;
|
|
|
|
if (pAce->AceFlags & INHERITED_ACE)
|
|
dwState |= CLST_DISABLED;
|
|
|
|
if (m_siPageType == SI_PAGE_ADVPERM)
|
|
{
|
|
// Only check one column (either allow or deny)
|
|
|
|
if (IsEqualACEType(pAce->AceType, ACCESS_ALLOWED_ACE_TYPE))
|
|
bColumnAllow = TRUE; // Access allowed
|
|
else if (IsEqualACEType(pAce->AceType, ACCESS_DENIED_ACE_TYPE))
|
|
bColumnDeny = TRUE; // Access denied
|
|
else
|
|
return -1; // Bogus ACE
|
|
}
|
|
else if (m_siPageType == SI_PAGE_AUDIT)
|
|
{
|
|
// Either or both columns can be checked for audits
|
|
|
|
if (pAce->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
|
|
bColumnAllow = TRUE; // Audit successful access
|
|
|
|
if (pAce->AceFlags & FAILED_ACCESS_ACE_FLAG)
|
|
bColumnDeny = TRUE; // Audit failed access
|
|
}
|
|
else
|
|
return -1;
|
|
|
|
cItems = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
|
|
|
|
while (cItems > 0)
|
|
{
|
|
PSI_ACCESS pAccess;
|
|
|
|
--cItems;
|
|
pAccess = (PSI_ACCESS)SendMessage(hwndList, CLM_GETITEMDATA, cItems, 0);
|
|
|
|
//
|
|
// The below expression tests to see if this access mask enables
|
|
// this access "rights" line. It could have more bits enabled, but
|
|
// as long as it has all of the ones from the pAccess->mask then
|
|
// it effectively has that option enabled.
|
|
//
|
|
|
|
if (pAccess &&
|
|
AllFlagsOn(pAce->Mask, pAccess->mask) &&
|
|
(!(pAce->Flags & ACE_OBJECT_TYPE_PRESENT) ||
|
|
IsSameGUID(pAccess->pguid, &pAce->ObjectType)))
|
|
{
|
|
WPARAM wItem;
|
|
|
|
nLastChecked = cItems;
|
|
|
|
|
|
if (bColumnAllow)
|
|
{
|
|
wItem = MAKELONG((WORD)cItems, COLUMN_ALLOW);
|
|
SendMessage(hwndList,
|
|
CLM_SETSTATE,
|
|
wItem,
|
|
(LPARAM)dwState);
|
|
}
|
|
|
|
if (bColumnDeny)
|
|
{
|
|
wItem = MAKELONG((WORD)cItems, COLUMN_DENY);
|
|
SendMessage(hwndList,
|
|
CLM_SETSTATE,
|
|
wItem,
|
|
(LPARAM)dwState);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nLastChecked;
|
|
}
|
|
|
|
|
|
LONG
|
|
CACEPage::InitCheckList(HWND hDlg, PACE pAce)
|
|
{
|
|
LONG nTopItemChecked;
|
|
HDPA hList = NULL;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::InitCheckList");
|
|
TraceAssert(hDlg != NULL);
|
|
|
|
if (m_siPageType == SI_PAGE_AUDIT)
|
|
SendDlgItemMessage(hDlg, IDC_ACEE_LIST, CLM_SETCOLUMNWIDTH, 0, 40);
|
|
|
|
hList = DPA_Create(1);
|
|
if (hList && pAce)
|
|
DPA_AppendPtr(hList, pAce->Copy());
|
|
|
|
nTopItemChecked = ReInitCheckList(hDlg, hList);
|
|
|
|
if (hList)
|
|
DestroyDPA(hList);
|
|
|
|
TraceLeaveValue(nTopItemChecked);
|
|
}
|
|
|
|
|
|
LONG
|
|
CACEPage::ReInitCheckList(HWND hDlg, HDPA hEntries)
|
|
{
|
|
LONG nTopItemChecked = -1;
|
|
HWND hwndList;
|
|
DWORD dwFlags;
|
|
HRESULT hr;
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::ReInitCheckList");
|
|
TraceAssert(hDlg != NULL);
|
|
|
|
hwndList = GetDlgItem(hDlg, IDC_ACEE_LIST);
|
|
|
|
EmptyCheckList(hwndList);
|
|
|
|
dwFlags = SI_ADVANCED;
|
|
|
|
if (m_siPageType == SI_PAGE_AUDIT)
|
|
dwFlags |= SI_EDIT_AUDITS;
|
|
|
|
if (m_siFlags == SI_ACCESS_PROPERTY)
|
|
dwFlags |= SI_EDIT_PROPERTIES;
|
|
|
|
//
|
|
// Enumerate the permissions and add to the checklist
|
|
//
|
|
hr = _InitCheckList(hwndList,
|
|
m_psi,
|
|
&m_guidInheritType,
|
|
dwFlags,
|
|
m_siObjectInfo.hInstance,
|
|
m_siFlags,
|
|
NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT cItems = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
|
|
|
|
//
|
|
//On object page display the message if number
|
|
//cItems is zero.
|
|
//
|
|
if(m_siFlags == SI_ACCESS_SPECIFIC)
|
|
DisplayNoControlMessage(hDlg, !cItems);
|
|
|
|
ULONG cAces = 0;
|
|
|
|
if (hEntries)
|
|
cAces = DPA_GetPtrCount(hEntries);
|
|
|
|
//
|
|
// Check the appropriate boxes
|
|
//
|
|
nTopItemChecked = MAXLONG;
|
|
while (cAces > 0)
|
|
{
|
|
PACE_HEADER pAceHeader;
|
|
|
|
--cAces;
|
|
pAceHeader = (PACE_HEADER)DPA_FastGetPtr(hEntries, cAces);
|
|
if (pAceHeader)
|
|
{
|
|
CAce Ace(pAceHeader);
|
|
LONG nTop = CheckPermBoxes(hwndList, &Ace, CLST_CHECKED);
|
|
if (-1 != nTop)
|
|
nTopItemChecked = min(nTopItemChecked, nTop);
|
|
}
|
|
}
|
|
if (MAXLONG == nTopItemChecked)
|
|
nTopItemChecked = -1;
|
|
|
|
// Make sure the top item checked is scrolled into view.
|
|
// (-1 scrolls to the top, same as 0.)
|
|
SendMessage(hwndList, CLM_ENSUREVISIBLE, nTopItemChecked, 0);
|
|
|
|
// Disable all of the boxes if we're in read-only mode
|
|
if (m_fReadOnly)
|
|
SendMessage(hwndList, WM_ENABLE, FALSE, 0);
|
|
}
|
|
|
|
SetCursor(hcur);
|
|
TraceLeaveValue(nTopItemChecked);
|
|
}
|
|
|
|
VOID CACEPage::DisplayNoControlMessage(HWND hDlg, BOOL bDisplay)
|
|
{
|
|
RECT rc;
|
|
if(bDisplay)
|
|
{
|
|
ShowWindow(m_hwndNoPerm, SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(m_hwndNoPerm, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
void CACEPage::HideInheritedAceWarning(HWND hDlg)
|
|
// Hides the message informing the user that the current ACE is inherited from
|
|
// the parent. Also moves and resizes controls as appropriate.
|
|
{
|
|
// Array of control IDs to move up
|
|
static UINT rgMoveControls[] =
|
|
{
|
|
IDC_ACEE_NAME_STATIC,
|
|
IDC_ACEE_NAME,
|
|
IDC_ACEE_NAMEBUTTON,
|
|
IDC_ACEE_APPLYONTO_STATIC,
|
|
IDC_ACEE_INHERITTYPE,
|
|
IDC_ACEE_ACCESS,
|
|
IDC_ACEE_ALLOW,
|
|
IDC_ACEE_DENY,
|
|
};
|
|
|
|
// Get the message window dimensions
|
|
HWND hwndControl = GetDlgItem(hDlg, IDC_ACEE_INHERITWARNING);
|
|
RECT rect;
|
|
GetWindowRect(hwndControl, &rect);
|
|
|
|
// We need to move controls up this amount:
|
|
int nMoveUpAmount = rect.bottom - rect.top;
|
|
|
|
// Rather than hide the message window, destroy it altogether so WinHelp
|
|
// doesn't confuse it with the "Name:" static during WM_CONTEXTMENU.
|
|
DestroyWindow(hwndControl);
|
|
|
|
// Move each of the controls we need to move up
|
|
for (int nControl = 0; nControl < ARRAYSIZE(rgMoveControls); nControl++)
|
|
{
|
|
hwndControl = GetDlgItem(hDlg, rgMoveControls[nControl]);
|
|
GetWindowRect(hwndControl, &rect);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rect, 2);
|
|
SetWindowPos(hwndControl,
|
|
NULL,
|
|
rect.left,
|
|
rect.top - nMoveUpAmount,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
|
|
// Finally, we need to resize the list control, including adjusting its height
|
|
hwndControl = GetDlgItem(hDlg, IDC_ACEE_LIST);
|
|
GetWindowRect(hwndControl, &rect);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rect, 2);
|
|
SetWindowPos(hwndControl,
|
|
NULL,
|
|
rect.left,
|
|
rect.top - nMoveUpAmount,
|
|
rect.right - rect.left,
|
|
rect.bottom - (rect.top - nMoveUpAmount),
|
|
SWP_NOZORDER);
|
|
}
|
|
|
|
|
|
//
|
|
// Default "Apply onto" strings for when GetInheritTypes
|
|
// fails or we don't find a matching inherit type.
|
|
//
|
|
// If desirable, different strings can be created for
|
|
// CONTAINER_INHERIT_ACE vs OBJECT_INHERIT_ACE.
|
|
//
|
|
static const UINT s_aInheritTypes[] =
|
|
{
|
|
IDS_THIS_OBJECT_ONLY, // 0 = <no inheritance>
|
|
IDS_THIS_OBJECT_AND_SUBOBJECTS, // 1 = OBJECT_INHERIT_ACE
|
|
IDS_THIS_OBJECT_AND_SUBOBJECTS, // 2 = CONTAINER_INHERIT_ACE
|
|
IDS_THIS_OBJECT_AND_SUBOBJECTS, // 3 = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
|
|
};
|
|
|
|
// These are used when INHERIT_ONLY_ACE is present
|
|
static const UINT s_aInheritOnlyTypes[] =
|
|
{
|
|
IDS_INVALID_INHERIT, // 0 = <invalid>
|
|
IDS_SUBOBJECTS_ONLY, // 1 = OBJECT_INHERIT_ACE
|
|
IDS_SUBOBJECTS_ONLY, // 2 = CONTAINER_INHERIT_ACE
|
|
IDS_SUBOBJECTS_ONLY, // 3 = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
|
|
};
|
|
|
|
|
|
static int
|
|
_AddInheritType(HWND hInheritType,
|
|
PSI_INHERIT_TYPE psiInheritType,
|
|
HINSTANCE hInstance)
|
|
{
|
|
UINT iIndex;
|
|
TCHAR szName[MAX_PATH];
|
|
LPCTSTR pszName = psiInheritType->pszName;
|
|
|
|
if (IS_INTRESOURCE(pszName))
|
|
{
|
|
if (LoadString(hInstance,
|
|
(ULONG)((ULONG_PTR)pszName),
|
|
szName,
|
|
ARRAYSIZE(szName)) == 0)
|
|
{
|
|
LoadString(::hModule,
|
|
IDS_UNKNOWN,
|
|
szName,
|
|
ARRAYSIZE(szName));
|
|
}
|
|
pszName = szName;
|
|
}
|
|
|
|
iIndex = (UINT)SendMessage(hInheritType, CB_ADDSTRING, 0, (LPARAM)pszName);
|
|
|
|
if (CB_ERR != iIndex)
|
|
SendMessage(hInheritType, CB_SETITEMDATA, iIndex, (LPARAM)psiInheritType);
|
|
|
|
return iIndex;
|
|
}
|
|
|
|
void
|
|
CACEPage::InitDlg(HWND hDlg)
|
|
{
|
|
#define X_COR 7
|
|
#define Y_COR 7
|
|
UCHAR AceFlags = 0;
|
|
PSID pSid = NULL;
|
|
LPCTSTR pszName = NULL;
|
|
LPTSTR pszNameT = NULL;
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
HRESULT hr;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::InitDlg");
|
|
|
|
//
|
|
//Store the hDlg
|
|
//
|
|
|
|
m_hwnd = hDlg;
|
|
if(m_siFlags == SI_ACCESS_SPECIFIC)
|
|
{
|
|
//
|
|
//Create a label to show message when no generic
|
|
//permissions exist for the object
|
|
//
|
|
|
|
WCHAR szName[1024];
|
|
LoadString(::hModule, IDS_NO_OBJECT_PERM, szName, ARRAYSIZE(szName));
|
|
|
|
RECT rc;
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ACEE_LIST),&rc);
|
|
// Create a new label control
|
|
m_hwndNoPerm = CreateWindowEx(0,
|
|
TEXT("STATIC"),
|
|
szName,
|
|
WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP | SS_NOPREFIX,
|
|
X_COR,
|
|
Y_COR,
|
|
rc.right - rc.left - 2*X_COR,
|
|
rc.bottom - rc.top - 2*Y_COR,
|
|
GetDlgItem(hDlg,IDC_ACEE_LIST),
|
|
(HMENU)IntToPtr(0xffff),
|
|
::hModule,
|
|
NULL);
|
|
// Set the font
|
|
SendMessage(m_hwndNoPerm,
|
|
WM_SETFONT,
|
|
SendMessage(hDlg, WM_GETFONT, 0, 0),
|
|
0);
|
|
}
|
|
|
|
|
|
if (m_pAce)
|
|
{
|
|
AceFlags = m_pAce->AceFlags;
|
|
m_guidInheritType = m_pAce->InheritedObjectType;
|
|
pSid = m_pAce->psid;
|
|
pszName = m_pAce->LookupName(m_siObjectInfo.pszServerName, m_psi2);
|
|
}
|
|
else
|
|
{
|
|
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
|
|
AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
|
|
|
pSid = QuerySystemSid(UI_SID_World);
|
|
}
|
|
|
|
// Make sure the AceFlags are valid
|
|
ACCESS_MASK Mask = 0;
|
|
m_psi->MapGeneric(&m_guidInheritType, &AceFlags, &Mask);
|
|
|
|
// Hide the inherit warning and adjust other control positions
|
|
if (!(AceFlags & INHERITED_ACE))
|
|
HideInheritedAceWarning(hDlg);
|
|
|
|
// Make a copy of the sid and get the name
|
|
if (pSid)
|
|
{
|
|
PUSER_LIST pUserList = NULL;
|
|
|
|
m_pSid = LocalAllocSid(pSid);
|
|
|
|
if (pszName == NULL)
|
|
{
|
|
// This should only happen when m_pAce is NULL and we're
|
|
// using UI_SID_World
|
|
if (LookupSid(pSid, m_siObjectInfo.pszServerName, m_psi2, &pUserList))
|
|
{
|
|
TraceAssert(NULL != pUserList);
|
|
TraceAssert(1 == pUserList->cUsers);
|
|
|
|
if (BuildUserDisplayName(&pszNameT,
|
|
pUserList->rgUsers[0].pszName,
|
|
pUserList->rgUsers[0].pszLogonName)
|
|
|| ConvertSidToStringSid(pSid, &pszNameT))
|
|
{
|
|
pszName = pszNameT;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_ACEE_NAME, pszName);
|
|
|
|
if (NULL != pUserList)
|
|
LocalFree(pUserList);
|
|
}
|
|
|
|
// Get the list of permissions and initialize the check boxes
|
|
InitCheckList(hDlg, m_pAce);
|
|
|
|
|
|
HWND hInheritType = GetDlgItem(hDlg, IDC_ACEE_INHERITTYPE);
|
|
HWND hInheritImmed = GetDlgItem(hDlg, IDC_ACEE_INHERITIMMEDIATE);
|
|
|
|
if (m_siObjectInfo.dwFlags & SI_NO_TREE_APPLY)
|
|
{
|
|
ShowWindow(hInheritImmed, SW_HIDE);
|
|
EnableWindow(hInheritImmed, FALSE);
|
|
}
|
|
|
|
//
|
|
// Get inherit types from callback
|
|
//
|
|
ULONG cItems = 0;
|
|
PSI_INHERIT_TYPE psiInheritType = NULL;
|
|
|
|
hr = m_psi->GetInheritTypes(&psiInheritType, &cItems);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// 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, &m_guidInheritType))
|
|
{
|
|
dwInheritMask &= ~INHERIT_ONLY_ACE;
|
|
}
|
|
|
|
//
|
|
// Add inherit types to combobox
|
|
//
|
|
for ( ; cItems > 0; cItems--, psiInheritType++)
|
|
{
|
|
UINT iIndex = _AddInheritType(hInheritType,
|
|
psiInheritType,
|
|
m_siObjectInfo.hInstance);
|
|
|
|
// See if this entry matches the incoming ACE
|
|
if ((psiInheritType->dwFlags & dwInheritMask) == (ULONG)(AceFlags & dwInheritMask)
|
|
&& IsSameGUID(&m_guidInheritType, psiInheritType->pguid))
|
|
{
|
|
// Got a match, select this entry
|
|
SendMessage(hInheritType, CB_SETCURSEL, iIndex, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If GetInheritTypes failed, or we failed to find a match,
|
|
// pick a default string and build an appropriate inherit type.
|
|
//
|
|
if (FAILED(hr) || CB_ERR == SendMessage(hInheritType, CB_GETCURSEL, 0, 0))
|
|
{
|
|
// Pick a default string
|
|
UINT ids = IDS_SPECIAL;
|
|
if (IsNullGUID(&m_guidInheritType))
|
|
{
|
|
if (AceFlags & INHERIT_ONLY_ACE)
|
|
ids = s_aInheritOnlyTypes[AceFlags & ACE_INHERIT_ALL];
|
|
else
|
|
ids = s_aInheritTypes[AceFlags & ACE_INHERIT_ALL];
|
|
}
|
|
|
|
// Fill in m_siInheritUnknown with the pertinent info
|
|
m_siInheritUnknown.pguid = &m_guidInheritType;
|
|
m_siInheritUnknown.dwFlags = AceFlags & (INHERIT_ONLY_ACE | ACE_INHERIT_ALL);
|
|
m_siInheritUnknown.pszName = MAKEINTRESOURCE(ids);
|
|
|
|
// Insert and select it
|
|
UINT iIndex = _AddInheritType(hInheritType,
|
|
&m_siInheritUnknown,
|
|
::hModule);
|
|
SendMessage(hInheritType, CB_SETCURSEL, iIndex, 0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// GetInheritTypes failed, which means the only entry is the
|
|
// default one we just added. Disable the combo.
|
|
EnableWindow(hInheritType, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Select the options which match the incoming ace
|
|
//
|
|
|
|
if (!(AceFlags & (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)))
|
|
{
|
|
SendMessage(hInheritImmed, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
EnableWindow(hInheritImmed, FALSE);
|
|
m_fInheritImmediateEnabled = FALSE;
|
|
m_fPreviousImmediateSetting = BST_UNCHECKED;
|
|
}
|
|
else
|
|
{
|
|
SendMessage(hInheritImmed,
|
|
BM_SETCHECK,
|
|
(AceFlags & NO_PROPAGATE_INHERIT_ACE) ? BST_CHECKED : BST_UNCHECKED,
|
|
0);
|
|
m_fInheritImmediateEnabled = TRUE;
|
|
}
|
|
|
|
if (!(m_siObjectInfo.dwFlags & SI_CONTAINER) || m_fReadOnly || (AceFlags & INHERITED_ACE))
|
|
{
|
|
// Disable all inheritance
|
|
EnableWindow(hInheritType, FALSE);
|
|
EnableWindow(hInheritImmed, FALSE);
|
|
}
|
|
|
|
if (m_fReadOnly || (AceFlags & INHERITED_ACE))
|
|
{
|
|
// Disable the "change name" and "clear all" buttons
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ACEE_NAMEBUTTON), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ACEE_CLEAR), FALSE);
|
|
}
|
|
|
|
PropSheet_QuerySiblings(GetParent(hDlg),0,(LPARAM)this);
|
|
|
|
LocalFreeString(&pszNameT);
|
|
SetCursor(hcur);
|
|
|
|
TraceLeaveVoid();
|
|
}
|
|
|
|
BOOL
|
|
CACEPage::OnChangeName(HWND hDlg)
|
|
{
|
|
PUSER_LIST pUserList = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::OnChangeName");
|
|
|
|
if (S_OK == GetUserGroup(hDlg, FALSE, &pUserList))
|
|
{
|
|
TraceAssert(NULL != pUserList);
|
|
TraceAssert(1 == pUserList->cUsers);
|
|
|
|
// Free up previous sid
|
|
if (m_pSid)
|
|
LocalFree(m_pSid);
|
|
|
|
// Copy the new sid
|
|
m_pSid = LocalAllocSid(pUserList->rgUsers[0].pSid);
|
|
if (m_pSid)
|
|
{
|
|
SetDlgItemText(hDlg, IDC_ACEE_NAME, pUserList->rgUsers[0].pszName);
|
|
bResult = TRUE;
|
|
}
|
|
LocalFree(pUserList);
|
|
}
|
|
|
|
TraceLeaveValue(bResult);
|
|
}
|
|
|
|
BOOL
|
|
CACEPage::OnClearAll(HWND hDlg)
|
|
{
|
|
HWND hwndList;
|
|
ULONG cPermissions;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::OnClearAll");
|
|
TraceAssert(!m_fReadOnly);
|
|
|
|
hwndList = GetDlgItem(hDlg, IDC_ACEE_LIST);
|
|
cPermissions = (ULONG)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
|
|
|
|
while (cPermissions != 0)
|
|
{
|
|
WORD wCol = COLUMN_ALLOW;
|
|
|
|
cPermissions--;
|
|
|
|
while (wCol == COLUMN_ALLOW || wCol == COLUMN_DENY)
|
|
{
|
|
WPARAM wItem = MAKELONG((WORD)cPermissions, wCol);
|
|
|
|
if (!(CLST_DISABLED & SendMessage(hwndList, CLM_GETSTATE, wItem, 0)))
|
|
SendMessage(hwndList, CLM_SETSTATE, wItem, CLST_UNCHECKED);
|
|
|
|
wCol++;
|
|
}
|
|
}
|
|
|
|
TraceLeaveValue(TRUE);
|
|
}
|
|
|
|
void
|
|
CACEPage::HandleSelChange(HWND hDlg, HWND hWnd) // inherit type change
|
|
{
|
|
PSI_INHERIT_TYPE psiInheritType;
|
|
BOOL fEnableInheritImmediate = FALSE;
|
|
const GUID *pguidInheritType = &GUID_NULL;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::HandleSelChange");
|
|
|
|
psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hWnd,
|
|
CB_GETITEMDATA,
|
|
SendMessage(hWnd, CB_GETCURSEL, 0, 0),
|
|
0);
|
|
|
|
if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
|
|
{
|
|
if (psiInheritType->dwFlags & (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE))
|
|
fEnableInheritImmediate = TRUE;
|
|
if( psiInheritType->pguid )
|
|
pguidInheritType = psiInheritType->pguid;
|
|
}
|
|
|
|
if (fEnableInheritImmediate != m_fInheritImmediateEnabled)
|
|
{
|
|
HWND hInheritImmediate = GetDlgItem(hDlg, IDC_ACEE_INHERITIMMEDIATE);
|
|
|
|
if (fEnableInheritImmediate)
|
|
{
|
|
SendMessage(hInheritImmediate, BM_SETCHECK, m_fPreviousImmediateSetting, 0);
|
|
}
|
|
else
|
|
{
|
|
m_fPreviousImmediateSetting = (BOOL)SendMessage(hInheritImmediate,
|
|
BM_GETCHECK,
|
|
0,
|
|
0);
|
|
SendMessage(hInheritImmediate, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
}
|
|
|
|
EnableWindow(hInheritImmediate, fEnableInheritImmediate);
|
|
m_fInheritImmediateEnabled = fEnableInheritImmediate;
|
|
}
|
|
|
|
// If the inherit type GUID has changed, reinitialize the checklist.
|
|
if (!IsSameGUID(pguidInheritType, &m_guidInheritType))
|
|
{
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
HDPA hNewEntries = DPA_Create(4);
|
|
|
|
if (hNewEntries)
|
|
{
|
|
GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
|
|
m_pSid,
|
|
m_siPageType == SI_PAGE_ADVPERM,
|
|
TRUE,
|
|
0, // don't care about flags
|
|
NULL, // or inherit type here
|
|
hNewEntries);
|
|
|
|
// Save new inherit type and reset the checklist
|
|
m_guidInheritType = *pguidInheritType;
|
|
ReInitCheckList(hDlg, hNewEntries);
|
|
DestroyDPA(hNewEntries);
|
|
}
|
|
|
|
SetCursor(hcur);
|
|
}
|
|
|
|
TraceLeaveVoid();
|
|
}
|
|
|
|
void
|
|
HandleListClick(PNM_CHECKLIST pnmc,
|
|
SI_PAGE_TYPE siType,
|
|
BOOL bInheritFlags,
|
|
HDSA *phAllowUncheckedAccess,
|
|
HDSA *phDenyUncheckedAccess,
|
|
BOOL bCustomPresent)
|
|
{
|
|
HWND hChkList;
|
|
UINT iRow;
|
|
WORD wCol;
|
|
PSI_ACCESS pAccess;
|
|
DWORD dwState;
|
|
BOOL bNullGuid;
|
|
UINT iRowCompare;
|
|
PSI_ACCESS pAccessCompare;
|
|
|
|
TraceEnter(TRACE_MISC, "HandleListClick");
|
|
TraceAssert(pnmc != NULL);
|
|
|
|
hChkList = pnmc->hdr.hwndFrom;
|
|
iRow = pnmc->iItem;
|
|
wCol = (WORD)pnmc->iSubItem; // 1 = Allow, 2 = Deny
|
|
pAccess = (PSI_ACCESS)pnmc->dwItemData;
|
|
dwState = pnmc->dwState;
|
|
|
|
if (pAccess == NULL)
|
|
TraceLeaveVoid();
|
|
|
|
if( phAllowUncheckedAccess )
|
|
{
|
|
*phAllowUncheckedAccess = DSA_Create(SIZEOF(PSI_ACCESS), 4);
|
|
if (*phAllowUncheckedAccess == NULL)
|
|
{
|
|
TraceMsg("DSA_Create failed");
|
|
TraceLeaveVoid();
|
|
}
|
|
}
|
|
if( phDenyUncheckedAccess )
|
|
{
|
|
*phDenyUncheckedAccess = DSA_Create(SIZEOF(PSI_ACCESS), 4);
|
|
if (*phDenyUncheckedAccess == NULL)
|
|
{
|
|
TraceMsg("DSA_Create failed");
|
|
TraceLeaveVoid();
|
|
}
|
|
}
|
|
|
|
|
|
bNullGuid = IsNullGUID(pAccess->pguid);
|
|
|
|
iRowCompare = (UINT)SendMessage(hChkList, CLM_GETITEMCOUNT, 0, 0);
|
|
|
|
//Custom checkbox is handled Separately
|
|
if( bCustomPresent )
|
|
--iRowCompare;
|
|
|
|
while (iRowCompare != 0)
|
|
{
|
|
WPARAM wItem;
|
|
DWORD dwStateCompareOriginal;
|
|
DWORD dwStateCompare;
|
|
WORD wColCompare;
|
|
BOOL bSameGuid;
|
|
BOOL bNullGuidCompare;
|
|
|
|
--iRowCompare;
|
|
pAccessCompare = (PSI_ACCESS)SendMessage(hChkList, CLM_GETITEMDATA, iRowCompare, 0);
|
|
|
|
if (!pAccessCompare)
|
|
continue;
|
|
|
|
bSameGuid = IsSameGUID(pAccessCompare->pguid, pAccess->pguid);
|
|
bNullGuidCompare = IsNullGUID(pAccessCompare->pguid);
|
|
|
|
// If the GUIDs are incompatible, then we can't do anything
|
|
if (!(bSameGuid || bNullGuid || bNullGuidCompare))
|
|
continue;
|
|
|
|
//
|
|
// Yukky, complicated mechanism to determine whether to
|
|
// turn on or off the allow or deny check marks.
|
|
//
|
|
// REVIEW: This algorithm of changing check marks based on other
|
|
// checkmarks handles a lot of cases, but it doesn't handle a
|
|
// two good ones.
|
|
//
|
|
// (1) If you have a right which implies other rights and you turn,
|
|
// it off, then maybe we should turn off all of the implied ones
|
|
// too. For example, you turn off change (which is the combination
|
|
// of read and write) maybe we should turn off both read and write.
|
|
//
|
|
// (2) If you turn on all of the component rights of one which
|
|
// implies them all, then we should turn on that one (because
|
|
// it implies them all).
|
|
//
|
|
#ifdef NO_RADIOBUTTON_BEHAVIOR
|
|
wColCompare = wCol;
|
|
#else
|
|
for (wColCompare = COLUMN_ALLOW; wColCompare <= COLUMN_DENY; wColCompare++)
|
|
#endif
|
|
{
|
|
wItem = MAKELONG((WORD)iRowCompare, wColCompare);
|
|
dwStateCompareOriginal = (DWORD)SendMessage(hChkList, CLM_GETSTATE, wItem, 0);
|
|
|
|
//
|
|
// If the other box is disabled, then it represents an
|
|
// inherited right so don't do anything with it.
|
|
//
|
|
// nb: Depending on NO_RADIOBUTTON_BEHAVIOR, this may continue to the
|
|
// for(wColCompare) loop or the while(iRowCompare) loop as appropriate
|
|
//
|
|
if (dwStateCompareOriginal & CLST_DISABLED)
|
|
continue;
|
|
|
|
dwStateCompare = dwStateCompareOriginal;
|
|
|
|
if (dwState & CLST_CHECKED)
|
|
{
|
|
if (wCol == wColCompare)
|
|
{
|
|
//
|
|
// If this right implies some other right,
|
|
// then turn it on too.
|
|
//
|
|
if ((bSameGuid || bNullGuid) && AllFlagsOn(pAccess->mask, pAccessCompare->mask))
|
|
{
|
|
if (!bInheritFlags ||
|
|
AllFlagsOn(pAccess->dwFlags & ACE_INHERIT_ALL, pAccessCompare->dwFlags & ACE_INHERIT_ALL))
|
|
{
|
|
dwStateCompare |= CLST_CHECKED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef NO_RADIOBUTTON_BEHAVIOR
|
|
//
|
|
// If this right implies or is implied by some other
|
|
// right in the other column, then turn it off.
|
|
//
|
|
if ( (siType == SI_PAGE_PERM || siType == SI_PAGE_ADVPERM) &&
|
|
(((bSameGuid || bNullGuid) && AllFlagsOn(pAccess->mask, pAccessCompare->mask)) ||
|
|
((bSameGuid || bNullGuidCompare) && AllFlagsOn(pAccessCompare->mask, pAccess->mask))) )
|
|
{
|
|
if (!bInheritFlags ||
|
|
(AllFlagsOn(pAccessCompare->dwFlags & ACE_INHERIT_ALL, pAccess->dwFlags & ACE_INHERIT_ALL) ||
|
|
AllFlagsOn(pAccess->dwFlags & ACE_INHERIT_ALL, pAccessCompare->dwFlags & ACE_INHERIT_ALL)) )
|
|
{
|
|
dwStateCompare &= ~(CLST_CHECKED);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (wCol == wColCompare)
|
|
{
|
|
//
|
|
// If this right is implied by some other right, then
|
|
// turn it off too.
|
|
//
|
|
if ((bSameGuid || bNullGuidCompare) && AllFlagsOn(pAccessCompare->mask, pAccess->mask))
|
|
{
|
|
if (!bInheritFlags ||
|
|
AllFlagsOn(pAccessCompare->dwFlags & ACE_INHERIT_ALL, pAccess->dwFlags & ACE_INHERIT_ALL))
|
|
{
|
|
dwStateCompare &= ~(CLST_CHECKED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwStateCompareOriginal != dwStateCompare)
|
|
{
|
|
SendMessage(hChkList, CLM_SETSTATE, wItem, (LPARAM)dwStateCompare);
|
|
//If a checkbox was intially checked and and now unchecked, add to
|
|
//h[Allow|Deny]UncheckedAccess.
|
|
if( dwStateCompareOriginal & CLST_CHECKED && !(dwStateCompare & CLST_CHECKED) )
|
|
{
|
|
if( phDenyUncheckedAccess && ( wColCompare == COLUMN_DENY ) )
|
|
DSA_AppendItem(*phDenyUncheckedAccess, &pAccessCompare);
|
|
if( phAllowUncheckedAccess && ( wColCompare == COLUMN_ALLOW ) )
|
|
DSA_AppendItem(*phAllowUncheckedAccess, &pAccessCompare);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceLeaveVoid();
|
|
}
|
|
|
|
|
|
UINT
|
|
GetAcesFromCheckList(HWND hChkList,
|
|
PSID pSid, // All aces get this SID
|
|
BOOL fPerm, // Create ACCESS or AUDIT aces?
|
|
BOOL fAceFlagsProvided, // Use uAceFlagsAll instead of pAccess->dwFlags
|
|
UCHAR uAceFlagsAll, // All aces get these flags
|
|
const GUID *pInheritGUID, // All aces get this inherit GUID
|
|
HDPA hEntries) // Store new aces here
|
|
{
|
|
UINT cCheckRows;
|
|
UINT iCheckRow;
|
|
UINT cbSidSize;
|
|
UINT iCount;
|
|
BOOL bInheritTypePresent = FALSE;
|
|
|
|
TraceEnter(TRACE_MISC, "GetAcesFromCheckList");
|
|
TraceAssert(hChkList != NULL);
|
|
TraceAssert(pSid != NULL);
|
|
TraceAssert(hEntries != NULL);
|
|
|
|
cbSidSize = GetLengthSid(pSid);
|
|
|
|
if (pInheritGUID == NULL)
|
|
pInheritGUID = &GUID_NULL;
|
|
else if (!IsNullGUID(pInheritGUID))
|
|
bInheritTypePresent = TRUE;
|
|
|
|
//
|
|
// First clear out the old HDPA
|
|
//
|
|
iCount = DPA_GetPtrCount(hEntries);
|
|
while (iCount != 0)
|
|
{
|
|
--iCount;
|
|
LocalFree(DPA_FastGetPtr(hEntries, iCount));
|
|
DPA_DeletePtr(hEntries, iCount);
|
|
}
|
|
|
|
cCheckRows = (UINT)SendMessage(hChkList, CLM_GETITEMCOUNT, 0, 0);
|
|
for (iCheckRow = 0; iCheckRow < cCheckRows; iCheckRow++)
|
|
{
|
|
PSI_ACCESS pAccess;
|
|
DWORD dwObjectFlagsNew;
|
|
WORD wCol;
|
|
UCHAR uAceFlagsNew;
|
|
|
|
pAccess = (PSI_ACCESS)SendMessage(hChkList, CLM_GETITEMDATA, iCheckRow, 0);
|
|
|
|
uAceFlagsNew = (UCHAR)(fAceFlagsProvided ? uAceFlagsAll : pAccess->dwFlags);
|
|
|
|
dwObjectFlagsNew = 0;
|
|
if (!IsNullGUID(pAccess->pguid))
|
|
dwObjectFlagsNew |= ACE_OBJECT_TYPE_PRESENT;
|
|
|
|
if (bInheritTypePresent)
|
|
dwObjectFlagsNew |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
|
|
|
|
wCol = COLUMN_ALLOW;
|
|
while (wCol == COLUMN_ALLOW || wCol == COLUMN_DENY)
|
|
{
|
|
WPARAM wItem;
|
|
DWORD dwState;
|
|
|
|
wItem = MAKELONG((WORD)iCheckRow, wCol);
|
|
dwState = (DWORD)SendMessage(hChkList, CLM_GETSTATE, wItem, 0);
|
|
|
|
if ((dwState & CLST_CHECKED) && !(dwState & CLST_DISABLED))
|
|
{
|
|
//
|
|
// Ok, time to make an ACE for this check mark, see if we
|
|
// can merge it into an already existing ACE, or whether we
|
|
// we need to create a new entry
|
|
//
|
|
UCHAR uAceTypeNew;
|
|
DWORD dwMaskNew = pAccess->mask;
|
|
UINT cbSize = SIZEOF(KNOWN_ACE);
|
|
|
|
if (fPerm)
|
|
{
|
|
if (wCol == COLUMN_ALLOW)
|
|
uAceTypeNew = ACCESS_ALLOWED_ACE_TYPE;
|
|
else
|
|
uAceTypeNew = ACCESS_DENIED_ACE_TYPE;
|
|
}
|
|
else
|
|
{
|
|
uAceTypeNew = SYSTEM_AUDIT_ACE_TYPE;
|
|
uAceFlagsNew &= ~(SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG);
|
|
|
|
if (wCol == COLUMN_ALLOW)
|
|
uAceFlagsNew |= SUCCESSFUL_ACCESS_ACE_FLAG;
|
|
else
|
|
uAceFlagsNew |= FAILED_ACCESS_ACE_FLAG;
|
|
}
|
|
|
|
if (dwObjectFlagsNew != 0)
|
|
{
|
|
uAceTypeNew += (ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE);
|
|
cbSize = SIZEOF(KNOWN_OBJECT_ACE);
|
|
|
|
if (dwObjectFlagsNew & ACE_OBJECT_TYPE_PRESENT)
|
|
cbSize += SIZEOF(GUID);
|
|
|
|
if (dwObjectFlagsNew & ACE_INHERITED_OBJECT_TYPE_PRESENT)
|
|
cbSize += SIZEOF(GUID);
|
|
}
|
|
|
|
cbSize += cbSidSize - SIZEOF(ULONG);
|
|
|
|
//
|
|
// See if it exists
|
|
//
|
|
iCount = DPA_GetPtrCount(hEntries);
|
|
while(iCount != 0)
|
|
{
|
|
PACE_HEADER pAce;
|
|
BOOL bObjectTypePresent = FALSE;
|
|
const GUID *pObjectType = NULL;
|
|
|
|
--iCount;
|
|
pAce = (PACE_HEADER)DPA_FastGetPtr(hEntries, iCount);
|
|
|
|
if (IsObjectAceType(pAce))
|
|
pObjectType = RtlObjectAceObjectType(pAce);
|
|
|
|
if (!pObjectType)
|
|
pObjectType = &GUID_NULL;
|
|
else
|
|
bObjectTypePresent = TRUE;
|
|
|
|
//
|
|
// Test the new ACE against each existing ACE to see if
|
|
// we can combine them.
|
|
//
|
|
if (IsEqualACEType(pAce->AceType, uAceTypeNew))
|
|
{
|
|
DWORD dwMergeFlags = 0;
|
|
DWORD dwMergeStatus;
|
|
DWORD dwMergeResult;
|
|
|
|
if (dwObjectFlagsNew & ACE_OBJECT_TYPE_PRESENT)
|
|
dwMergeFlags |= MF_OBJECT_TYPE_1_PRESENT;
|
|
|
|
if (bObjectTypePresent)
|
|
dwMergeFlags |= MF_OBJECT_TYPE_2_PRESENT;
|
|
|
|
if (!(dwMergeFlags & (MF_OBJECT_TYPE_1_PRESENT | MF_OBJECT_TYPE_2_PRESENT)))
|
|
{
|
|
// Neither are present, so they are the same
|
|
dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
|
|
}
|
|
else if (IsSameGUID(pAccess->pguid, pObjectType))
|
|
dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
|
|
|
|
if (!fPerm)
|
|
dwMergeFlags |= MF_AUDIT_ACE_TYPE;
|
|
|
|
dwMergeStatus = MergeAceHelper(uAceFlagsNew,
|
|
dwMaskNew,
|
|
pAce->AceFlags,
|
|
((PKNOWN_ACE)pAce)->Mask,
|
|
dwMergeFlags,
|
|
&dwMergeResult);
|
|
|
|
if (dwMergeStatus == MERGE_MODIFIED_FLAGS)
|
|
{
|
|
uAceFlagsNew = (UCHAR)dwMergeResult;
|
|
dwMergeStatus = MERGE_OK_1;
|
|
}
|
|
else if (dwMergeStatus == MERGE_MODIFIED_MASK)
|
|
{
|
|
dwMaskNew = dwMergeResult;
|
|
dwMergeStatus = MERGE_OK_1;
|
|
}
|
|
|
|
if (dwMergeStatus == MERGE_OK_1)
|
|
{
|
|
//
|
|
// The new ACE implies the existing ACE, so
|
|
// the existing one can be removed.
|
|
//
|
|
LocalFree(pAce);
|
|
DPA_DeletePtr(hEntries, iCount);
|
|
//
|
|
// Keep looking. Maybe we can remove some more entries
|
|
// before adding the new one.
|
|
//
|
|
}
|
|
else if (dwMergeStatus == MERGE_OK_2)
|
|
{
|
|
iCount = 1; // non-zero for match found
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Otherwise, add it
|
|
//
|
|
if (iCount == 0)
|
|
{
|
|
PACE_HEADER pAce = (PACE_HEADER)LocalAlloc(LPTR, cbSize);
|
|
|
|
if (pAce)
|
|
{
|
|
PSID pSidT;
|
|
|
|
pAce->AceType = uAceTypeNew;
|
|
pAce->AceFlags = uAceFlagsNew;
|
|
pAce->AceSize = (USHORT)cbSize;
|
|
((PKNOWN_ACE)pAce)->Mask = dwMaskNew;
|
|
pSidT = &((PKNOWN_ACE)pAce)->SidStart;
|
|
|
|
if (dwObjectFlagsNew != 0)
|
|
{
|
|
GUID *pGuid;
|
|
|
|
((PKNOWN_OBJECT_ACE)pAce)->Flags = dwObjectFlagsNew;
|
|
|
|
pGuid = RtlObjectAceObjectType(pAce);
|
|
if (pGuid)
|
|
{
|
|
if (pAccess->pguid)
|
|
*pGuid = *pAccess->pguid;
|
|
else
|
|
*pGuid = GUID_NULL;
|
|
}
|
|
|
|
pGuid = RtlObjectAceInheritedObjectType(pAce);
|
|
if (pGuid)
|
|
*pGuid = *pInheritGUID;
|
|
|
|
pSidT = RtlObjectAceSid(pAce);
|
|
}
|
|
|
|
CopyMemory(pSidT, pSid, cbSidSize);
|
|
DPA_AppendPtr(hEntries, pAce);
|
|
}
|
|
}
|
|
}
|
|
|
|
wCol++;
|
|
}
|
|
}
|
|
|
|
iCount = DPA_GetPtrCount(hEntries);
|
|
TraceLeaveValue(iCount);
|
|
}
|
|
|
|
LONG
|
|
CACEPage::OnApply(HWND hDlg, BOOL /*bClose*/)
|
|
{
|
|
const GUID *pInheritGUID;
|
|
UCHAR uAceFlagsNew = 0;
|
|
HDPA hEntries;
|
|
BOOL bAclBloated = FALSE;
|
|
//
|
|
//If this page is property page and user has not clicked on
|
|
//the object page, aclbloat must be checked from this page
|
|
//only.
|
|
//
|
|
if((m_siFlags == SI_ACCESS_PROPERTY) && !m_pOtherPage)
|
|
bAclBloated = IsAclBloated(hDlg);
|
|
|
|
if(m_siFlags != SI_ACCESS_PROPERTY)
|
|
bAclBloated = IsAclBloated(hDlg);
|
|
|
|
if(bAclBloated)
|
|
return PSNRET_INVALID_NOCHANGEPAGE;
|
|
|
|
if (!m_fPageDirty)
|
|
return PSNRET_NOERROR;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::Apply");
|
|
|
|
|
|
|
|
//
|
|
// Determine inheritance for containers
|
|
//
|
|
pInheritGUID = &GUID_NULL;
|
|
if ((m_siObjectInfo.dwFlags & SI_CONTAINER) != 0)
|
|
{
|
|
PSI_INHERIT_TYPE psiInheritType = NULL;
|
|
HWND hInheritType = GetDlgItem( hDlg, IDC_ACEE_INHERITTYPE);
|
|
|
|
int iSel = (int)SendMessage(hInheritType, CB_GETCURSEL, 0,0);
|
|
|
|
if (iSel != CB_ERR)
|
|
{
|
|
psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hInheritType,
|
|
CB_GETITEMDATA,
|
|
iSel,
|
|
0);
|
|
}
|
|
|
|
if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
|
|
{
|
|
pInheritGUID = psiInheritType->pguid;
|
|
uAceFlagsNew = (UCHAR)(psiInheritType->dwFlags & VALID_INHERIT_FLAGS);
|
|
}
|
|
else if (m_pAce)
|
|
{
|
|
uAceFlagsNew = m_pAce->AceFlags;
|
|
}
|
|
|
|
if (m_fInheritImmediateEnabled)
|
|
{
|
|
if (IsDlgButtonChecked(hDlg, IDC_ACEE_INHERITIMMEDIATE) == BST_CHECKED)
|
|
uAceFlagsNew |= NO_PROPAGATE_INHERIT_ACE;
|
|
else
|
|
uAceFlagsNew &= ~NO_PROPAGATE_INHERIT_ACE;
|
|
}
|
|
}
|
|
|
|
if (m_phEntries != NULL)
|
|
{
|
|
if (*m_phEntries == NULL)
|
|
*m_phEntries = DPA_Create(4);
|
|
|
|
GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
|
|
m_pSid,
|
|
m_siPageType == SI_PAGE_ADVPERM,
|
|
TRUE,
|
|
uAceFlagsNew,
|
|
pInheritGUID,
|
|
*m_phEntries);
|
|
}
|
|
|
|
if (m_pdwResult)
|
|
*m_pdwResult |= (m_siFlags == SI_ACCESS_PROPERTY ? EAE_NEW_PROPERTY_ACE : EAE_NEW_OBJECT_ACE);
|
|
m_fPageDirty = FALSE;
|
|
|
|
TraceLeaveValue(PSNRET_NOERROR);
|
|
}
|
|
|
|
BOOL
|
|
CACEPage::IsAclBloated(HWND hDlg)
|
|
{
|
|
TraceEnter(TRACE_MISC, "CACEPage::ShowAclBloat");
|
|
|
|
HDPA hEntries = NULL;
|
|
HDPA hPropEntries = NULL;
|
|
|
|
BOOL bReturn = FALSE;
|
|
|
|
hEntries = GetAceList(hDlg);
|
|
|
|
if(m_pOtherPage)
|
|
{
|
|
hPropEntries = m_pOtherPage->GetAceList(m_pOtherPage->m_hwnd);
|
|
}
|
|
|
|
CACLBloat bloat(m_psi,
|
|
m_psi2,
|
|
m_siPageType,
|
|
&m_siObjectInfo,
|
|
hEntries,
|
|
hPropEntries);
|
|
if(bloat.IsAclBloated())
|
|
bReturn = bloat.DoModalDialog(hDlg);
|
|
|
|
if(hEntries)
|
|
DestroyDPA(hEntries);
|
|
|
|
if(hPropEntries)
|
|
DestroyDPA(hPropEntries);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
HDPA
|
|
CACEPage::GetAceList(HWND hDlg)
|
|
{
|
|
TraceEnter(TRACE_ACEEDIT, "CACEPage::GetAceList");
|
|
|
|
if (!m_fPageDirty)
|
|
return NULL;
|
|
//
|
|
// Determine inheritance for containers
|
|
//
|
|
const GUID *pInheritGUID = &GUID_NULL;
|
|
UCHAR uAceFlagsNew = 0;
|
|
HDPA hEntries = NULL;
|
|
|
|
if ((m_siObjectInfo.dwFlags & SI_CONTAINER) != 0)
|
|
{
|
|
PSI_INHERIT_TYPE psiInheritType = NULL;
|
|
HWND hInheritType = GetDlgItem( hDlg, IDC_ACEE_INHERITTYPE);
|
|
|
|
int iSel = (int)SendMessage(hInheritType, CB_GETCURSEL, 0,0);
|
|
|
|
if (iSel != CB_ERR)
|
|
{
|
|
psiInheritType = (PSI_INHERIT_TYPE)SendMessage(hInheritType,
|
|
CB_GETITEMDATA,
|
|
iSel,
|
|
0);
|
|
}
|
|
|
|
if (psiInheritType != (PSI_INHERIT_TYPE)CB_ERR && psiInheritType != NULL)
|
|
{
|
|
pInheritGUID = psiInheritType->pguid;
|
|
uAceFlagsNew = (UCHAR)(psiInheritType->dwFlags & VALID_INHERIT_FLAGS);
|
|
}
|
|
else if (m_pAce)
|
|
{
|
|
uAceFlagsNew = m_pAce->AceFlags;
|
|
}
|
|
|
|
if (m_fInheritImmediateEnabled)
|
|
{
|
|
if (IsDlgButtonChecked(hDlg, IDC_ACEE_INHERITIMMEDIATE) == BST_CHECKED)
|
|
uAceFlagsNew |= NO_PROPAGATE_INHERIT_ACE;
|
|
else
|
|
uAceFlagsNew &= ~NO_PROPAGATE_INHERIT_ACE;
|
|
}
|
|
}
|
|
|
|
hEntries = DPA_Create(4);
|
|
|
|
if(hEntries)
|
|
{
|
|
GetAcesFromCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST),
|
|
m_pSid,
|
|
m_siPageType == SI_PAGE_ADVPERM,
|
|
TRUE,
|
|
uAceFlagsNew,
|
|
pInheritGUID,
|
|
hEntries);
|
|
}
|
|
return hEntries;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CACEPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
InitDlg(hDlg);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
EmptyCheckList(GetDlgItem(hDlg, IDC_ACEE_LIST));
|
|
break;
|
|
|
|
case PWM_SELECT_PAGE:
|
|
PropSheet_SetCurSel(GetParent(hDlg), lParam, wParam);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDC_ACEE_NAMEBUTTON:
|
|
if (OnChangeName(hDlg))
|
|
{
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
m_fPageDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDC_ACEE_INHERITTYPE:
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
|
|
{
|
|
HandleSelChange(hDlg, (HWND)lParam);
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
m_fPageDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDC_ACEE_INHERITIMMEDIATE:
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
|
|
{
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
m_fPageDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDC_ACEE_CLEAR:
|
|
if (OnClearAll(hDlg))
|
|
{
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
m_fPageDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
case CLN_CLICK:
|
|
if (lParam)
|
|
{
|
|
HandleListClick((PNM_CHECKLIST)lParam, m_siPageType, FALSE);
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
m_fPageDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
case CLN_GETCOLUMNDESC:
|
|
{
|
|
PNM_CHECKLIST pnmc = (PNM_CHECKLIST)lParam;
|
|
GetDlgItemText(hDlg,
|
|
IDC_ACEE_ALLOW - 1 + pnmc->iSubItem,
|
|
pnmc->pszText,
|
|
pnmc->cchTextMax);
|
|
}
|
|
break;
|
|
|
|
case PSN_APPLY:
|
|
SetWindowLongPtr(hDlg,
|
|
DWLP_MSGRESULT,
|
|
OnApply(hDlg, (BOOL)(((LPPSHNOTIFY)lParam)->lParam)));
|
|
break;
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
case PSM_QUERYSIBLINGS:
|
|
{
|
|
BOOL bSendQuery = !m_pOtherPage;
|
|
if(this != (CACEPage*)lParam)
|
|
m_pOtherPage = (CACEPage*)lParam;
|
|
|
|
if(bSendQuery)
|
|
PostMessage(GetParent(hDlg),PSM_QUERYSIBLINGS,0,(LPARAM)this);
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case WM_HELP:
|
|
if (IsWindowEnabled(hDlg))
|
|
{
|
|
const DWORD *pdwHelpIDs = aAcePermHelpIDs;
|
|
|
|
if (m_siPageType == SI_PAGE_AUDIT)
|
|
pdwHelpIDs = aAceAuditHelpIDs;
|
|
|
|
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
|
|
c_szAcluiHelpFile,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)pdwHelpIDs);
|
|
}
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
if (IsWindowEnabled(hDlg))
|
|
{
|
|
HWND hwnd = (HWND)wParam;
|
|
const DWORD *pdwHelpIDs = aAcePermHelpIDs;
|
|
|
|
if (m_siPageType == SI_PAGE_AUDIT)
|
|
pdwHelpIDs = aAceAuditHelpIDs;
|
|
|
|
//
|
|
// Some of the checkboxes may be scrolled out of view, but
|
|
// they are still detected by WinHelp, so we jump through
|
|
// a few extra hoops here.
|
|
//
|
|
if (hwnd == hDlg)
|
|
{
|
|
POINT pt;
|
|
pt.x = GET_X_LPARAM(lParam);
|
|
pt.y = GET_Y_LPARAM(lParam);
|
|
|
|
ScreenToClient(hDlg, &pt);
|
|
hwnd = ChildWindowFromPoint(hDlg, pt);
|
|
if (hDlg == hwnd)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// WinHelp looks for child windows, but we don't have help id's
|
|
// for the permission checkboxes. If the request is for the
|
|
// checklist window, fake out WinHelp by referring to one of
|
|
// the static labels just above the list.
|
|
//
|
|
if (GetDlgCtrlID(hwnd) == IDC_ACEE_LIST)
|
|
hwnd = GetWindow((HWND)wParam, GW_HWNDPREV); // Static label "Deny"
|
|
|
|
WinHelp(hwnd,
|
|
c_szAcluiHelpFile,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)pdwHelpIDs);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HPROPSHEETPAGE
|
|
CreateACEPage(LPSECURITYINFO psi,
|
|
SI_PAGE_TYPE siType,
|
|
PACE pAce,
|
|
BOOL bReadOnly,
|
|
DWORD dwFlags,
|
|
DWORD *pdwResult,
|
|
HDPA *phEntries)
|
|
{
|
|
HPROPSHEETPAGE hPage = NULL;
|
|
LPCTSTR pszTitle = NULL;
|
|
LPACEPAGE pPage;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "CreateACEPage");
|
|
TraceAssert(psi != NULL);
|
|
TraceAssert(phEntries != NULL);
|
|
|
|
pPage = new CACEPage(psi,
|
|
siType,
|
|
pAce,
|
|
bReadOnly,
|
|
dwFlags,
|
|
pdwResult,
|
|
phEntries);
|
|
if (pPage)
|
|
{
|
|
int iDlgTemplate = IDD_ACEENTRY_PERM_PAGE;
|
|
|
|
if (siType == SI_PAGE_AUDIT)
|
|
iDlgTemplate = IDD_ACEENTRY_AUDIT_PAGE;
|
|
|
|
if (dwFlags == SI_ACCESS_PROPERTY)
|
|
pszTitle = MAKEINTRESOURCE(IDS_ACEE_PROPERTY_TITLE);
|
|
|
|
hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(iDlgTemplate), pszTitle);
|
|
}
|
|
|
|
TraceLeaveValue(hPage);
|
|
}
|
|
|
|
BOOL
|
|
EditACEEntry(HWND hwndOwner,
|
|
LPSECURITYINFO psi,
|
|
PACE pAce,
|
|
SI_PAGE_TYPE siType,
|
|
LPCTSTR pszObjectName,
|
|
BOOL bReadOnly,
|
|
DWORD *pdwResult,
|
|
HDPA *phEntries,
|
|
HDPA *phPropertyEntries,
|
|
UINT nStartPage)
|
|
{
|
|
HPROPSHEETPAGE hPage[2];
|
|
UINT cPages = 0;
|
|
BOOL bResult = FALSE;
|
|
|
|
TraceEnter(TRACE_ACEEDIT, "EditACEEntry");
|
|
TraceAssert(psi != NULL);
|
|
|
|
if (phEntries)
|
|
{
|
|
hPage[cPages] = CreateACEPage(psi,
|
|
siType,
|
|
pAce,
|
|
bReadOnly,
|
|
SI_ACCESS_SPECIFIC,
|
|
pdwResult,
|
|
phEntries);
|
|
if (hPage[cPages])
|
|
cPages++;
|
|
}
|
|
|
|
if (phPropertyEntries)
|
|
{
|
|
hPage[cPages] = CreateACEPage(psi,
|
|
siType,
|
|
pAce,
|
|
bReadOnly,
|
|
SI_ACCESS_PROPERTY,
|
|
pdwResult,
|
|
phPropertyEntries);
|
|
if (hPage[cPages])
|
|
cPages++;
|
|
}
|
|
|
|
if (cPages)
|
|
{
|
|
// Build dialog title string
|
|
LPTSTR pszCaption = NULL;
|
|
FormatStringID(&pszCaption,
|
|
::hModule,
|
|
siType == SI_PAGE_AUDIT ? IDS_ACEE_AUDIT_TITLE : IDS_ACEE_PERM_TITLE,
|
|
pszObjectName);
|
|
|
|
PROPSHEETHEADER psh;
|
|
psh.dwSize = SIZEOF(psh);
|
|
psh.dwFlags = PSH_DEFAULT | PSH_NOAPPLYNOW;
|
|
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 = (PropertySheet(&psh) == IDOK);
|
|
|
|
LocalFreeString(&pszCaption);
|
|
}
|
|
|
|
TraceLeaveValue(bResult);
|
|
}
|