windows-nt/Source/XPSP1/NT/shell/osshell/security/aclui/perm.cpp

3354 lines
101 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "aclpriv.h"
//Function for checking the Custom checkbox
VOID
CheckCustom(HWND hwndList,
WORD wColumn, //Allow or Deny column
DWORD dwState )
{
//Custom is always the last checkbox
UINT cRights = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
//Don't check if the column is already checked. This fucntion is first
//called for explicit and then for inherited aces. Effect is if explict aces are there
//checkbox is enabled.
DWORD dwStateCurrent = (DWORD)SendMessage(hwndList,
CLM_GETSTATE,
MAKELONG((WORD)(cRights -1), wColumn),
0);
if (dwStateCurrent & CLST_CHECKED)
return;
//
//Custom Checkbox is always disabled
//
SendMessage(hwndList,
CLM_SETSTATE,
MAKELONG((WORD)(cRights -1), wColumn),
dwState|CLST_DISABLED);
}
VOID
ClearCustom(HWND hwndList,
WORD wColumn) //Allow or Deny column
{
//Custom is always the last checkbox
UINT cRights = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
//
//Custom Checkbox is always disabled
//
SendMessage(hwndList,
CLM_SETSTATE,
MAKELONG((WORD)(cRights -1), wColumn),
CLST_DISABLED);
}
//
// CPrincipal implementation
//
CPrincipal::~CPrincipal()
{
if (NULL != m_pSID)
LocalFree(m_pSID);
LocalFreeString(&m_pszName);
LocalFreeString(&m_pszDisplayName);
if( m_hAdditionalAllow != NULL )
DSA_Destroy( m_hAdditionalAllow );
if( m_hAdditionalDeny != NULL )
DSA_Destroy( m_hAdditionalDeny );
}
BOOL
CPrincipal::SetPrincipal(PSID pSID,
SID_NAME_USE sidType,
LPCTSTR pszName,
LPCTSTR pszLogonName)
{
DWORD dwLength;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::SetPrincipal");
TraceAssert(pSID != NULL);
TraceAssert(IsValidSid(pSID));
if (NULL != m_pSID)
LocalFree(m_pSID);
m_pSID = LocalAllocSid(pSID);
SetSidType(sidType);
SetName(pszName, pszLogonName);
TraceLeaveValue(NULL != m_pSID);
}
BOOL
CPrincipal::SetName(LPCTSTR pszName, LPCTSTR pszLogonName)
{
LocalFreeString(&m_pszName);
m_bHaveRealName = FALSE;
if (BuildUserDisplayName(&m_pszName, pszName, pszLogonName))
m_bHaveRealName = TRUE;
else
ConvertSidToStringSid(m_pSID, &m_pszName);
if(pszName)
{
LocalFreeString(&m_pszDisplayName);
LocalAllocString(&m_pszDisplayName, pszName);
}
return (NULL != m_pszName);
}
CPermissionSet*
CPrincipal::GetPermSet(DWORD dwType, BOOL bInherited)
{
CPermissionSet *pPermSet = NULL;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::GetPermSet");
switch (dwType)
{
case ACCESS_DENIED_ACE_TYPE:
if (bInherited)
pPermSet = &m_permInheritedDeny;
else
pPermSet = &m_permDeny;
break;
case ACCESS_ALLOWED_ACE_TYPE:
if (bInherited)
pPermSet = &m_permInheritedAllow;
else
pPermSet = &m_permAllow;
break;
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
// We don't handle compound ACEs
TraceMsg("Ignoring ACCESS_ALLOWED_COMPOUND_ACE");
break;
#ifdef DEBUG
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
default:
// We only process the various ACCESS_ALLOWED_* and ACCESS_DENIED_*
// ACE types, except for ACCESS_ALLOWED_COMPOUND_ACE_TYPE, and these
// are all accounted for above. Something is very wrong if we get
// an audit/alarm ACE or some unknown/future ACE type.
TraceAssert(FALSE);
break;
#endif
}
TraceLeaveValue(pPermSet);
}
BOOL
CPrincipal::AddNormalAce(DWORD dwType, DWORD dwFlags, ACCESS_MASK mask, const GUID *pObjectType)
{
BOOL fResult = FALSE;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::AddNormalAce");
CPermissionSet *pPermSet = GetPermSet(dwType, (BOOL)(dwFlags & INHERITED_ACE));
if (pPermSet)
fResult = pPermSet->AddAce(pObjectType, mask, dwFlags);
TraceLeaveValue(fResult);
}
BOOL
CPrincipal::AddAdvancedAce(DWORD dwType, PACE_HEADER pAce)
{
BOOL fResult = FALSE;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::AddAdvancedAce");
CPermissionSet *pPermSet = GetPermSet(dwType, AceInherited(pAce));
if (pPermSet)
fResult = pPermSet->AddAdvancedAce(pAce);
TraceLeaveValue(fResult);
}
BOOL
CPrincipal::AddAce(PACE_HEADER pAce)
{
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::AddAce");
TraceAssert(pAce != NULL);
BOOL fResult = FALSE;
const GUID *pObjectType = NULL;
UCHAR AceType = pAce->AceType;
UCHAR AceFlags = pAce->AceFlags;
ACCESS_MASK AccessMask = ((PKNOWN_ACE)pAce)->Mask;
ULONG ulObjectFlags = 0;
// Get the object type GUID from object ACEs
if (IsObjectAceType(pAce))
{
AceType -= (ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE);
ulObjectFlags = ((PKNOWN_OBJECT_ACE)pAce)->Flags;
if (m_pPage->m_wDaclRevision < ACL_REVISION_DS)
m_pPage->m_wDaclRevision = ACL_REVISION_DS;
pObjectType = RtlObjectAceObjectType(pAce);
}
if (!pObjectType)
pObjectType = &GUID_NULL;
// Map any generic bits to standard & specific bits.
m_pPage->m_psi->MapGeneric(pObjectType, &AceFlags, &AccessMask);
// Can't have INHERIT_ONLY_ACE without either CONTAINER_INHERIT_ACE or
// OBJECT_INHERIT_ACE, so if we find one of these, skip it.
if ((AceFlags & (INHERIT_ONLY_ACE | ACE_INHERIT_ALL)) != INHERIT_ONLY_ACE)
{
//
//ACE_INHERITED_OBJECT_TYPE_PRESENT is invalid without
//either of container inherit or object inherit flags.
//NTRAID#NTBUG9-287737-2001/01/23-hiteshr
//
if (ulObjectFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT &&
AceFlags & ACE_INHERIT_ALL)
{
// If we have an inherit object type without INHERIT_ONLY_ACE,
// and the inherit object type matches the current object,
// then it applies to this object. Simulate this (per the
// ACL inheritance spec) with 2 ACEs: one with no inheritance
// at all, and one with the inherit type + INHERIT_ONLY_ACE.
// Does it apply to this object?
if ((m_pPage->m_siObjectInfo.dwFlags & SI_OBJECT_GUID) &&
!(AceFlags & INHERIT_ONLY_ACE) &&
IsSameGUID(&m_pPage->m_siObjectInfo.guidObjectType, RtlObjectAceInheritedObjectType(pAce)))
{
// Mask out all flags except INHERITED_ACE and add it
AddNormalAce(AceType, (AceFlags & INHERITED_ACE), AccessMask, pObjectType);
// Turn on INHERIT_ONLY_ACE before adding the "advanced" ACE.
pAce->AceFlags |= INHERIT_ONLY_ACE;
}
// The ACE does not apply directly to this object
fResult = AddAdvancedAce(AceType, pAce);
}
else
{
fResult = AddNormalAce(AceType, AceFlags, AccessMask, pObjectType);
}
}
TraceLeaveValue(fResult);
}
ULONG
CPrincipal::GetAclLength(DWORD dwFlags)
{
// Return an estimate of the buffer size needed to hold the
// requested ACEs. The size of the ACL header is NOT INCLUDED.
// The following flags are always assumed:
// ACL_DENY | ACL_ALLOW | ACL_NONOBJECT | ACL_OBJECT
ULONG nAclLength = 0;
ULONG nSidLength;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::GetAclLength");
TraceAssert(NULL != m_pSID);
if (NULL == m_pSID)
TraceLeaveValue(0);
nSidLength = GetLengthSid(m_pSID);
if (dwFlags & ACL_NONINHERITED)
{
nAclLength += m_permDeny.GetAclLength(nSidLength);
nAclLength += m_permAllow.GetAclLength(nSidLength);
}
if (dwFlags & ACL_INHERITED)
{
nAclLength += m_permInheritedDeny.GetAclLength(nSidLength);
nAclLength += m_permInheritedAllow.GetAclLength(nSidLength);
}
TraceLeaveValue(nAclLength);
}
BOOL
CPrincipal::AppendToAcl(PACL pAcl,
DWORD dwFlags,
PACE_HEADER *ppAcePos) // position to copy first ACE
{
PACE_HEADER pAceT;
TraceEnter(TRACE_PRINCIPAL, "CPrincipal::AppendToAcl");
TraceAssert(pAcl != NULL && IsValidAcl(pAcl));
TraceAssert(ppAcePos != NULL);
TraceAssert(NULL != m_pSID);
if (NULL == m_pSID)
TraceLeaveValue(FALSE);
pAceT = *ppAcePos;
// Build the ACL in the following order:
// Deny
// Allow
// Inherited Deny
// Inherited Allow
if (dwFlags & ACL_NONINHERITED)
{
if (dwFlags & ACL_DENY)
m_permDeny.AppendToAcl(pAcl, ppAcePos, m_pSID, FALSE, dwFlags);
if (dwFlags & ACL_ALLOW)
m_permAllow.AppendToAcl(pAcl, ppAcePos, m_pSID, TRUE, dwFlags);
}
if (dwFlags & ACL_INHERITED)
{
if (dwFlags & ACL_DENY)
m_permInheritedDeny.AppendToAcl(pAcl, ppAcePos, m_pSID, FALSE, dwFlags);
if (dwFlags & ACL_ALLOW)
m_permInheritedAllow.AppendToAcl(pAcl, ppAcePos, m_pSID, TRUE, dwFlags);
}
if ((dwFlags & ACL_CHECK_CREATOR) && IsCreatorSid(m_pSID))
{
//
// Special case for CreatorOwner/CreatorGroup,
// which are only useful if inherit bits are set.
//
for (; pAceT < *ppAcePos; pAceT = (PACE_HEADER)NextAce(pAceT))
{
pAceT->AceFlags |= INHERIT_ONLY_ACE;
if (!(pAceT->AceFlags & ACE_INHERIT_ALL))
{
pAceT->AceFlags |= ACE_INHERIT_ALL;
//
// Give the client a chance to adjust the flags.
// E.g. DS always turns off OBJECT_INHERIT_ACE
//
UCHAR AceFlags = pAceT->AceFlags;
ACCESS_MASK Mask = GENERIC_ALL;
m_pPage->m_psi->MapGeneric(NULL, &AceFlags, &Mask);
pAceT->AceFlags = AceFlags;
}
}
}
TraceAssert(IsValidAcl(pAcl));
TraceLeaveValue(TRUE);
}
BOOL
CPrincipal::HaveInheritedAces(void)
{
return (m_permInheritedAllow.GetPermCount(TRUE) || m_permInheritedDeny.GetPermCount(TRUE));
}
void
CPrincipal::ConvertInheritedAces(BOOL bDelete)
{
if (bDelete)
{
m_permInheritedDeny.Reset();
m_permInheritedAllow.Reset();
}
else
{
m_permDeny.ConvertInheritedAces(m_permInheritedDeny);
m_permAllow.ConvertInheritedAces(m_permInheritedAllow);
}
}
void
CPrincipal::AddPermission(BOOL bAllow, PPERMISSION pperm)
{
if (bAllow)
m_permAllow.AddPermission(pperm);
else
m_permDeny.AddPermission(pperm);
}
void
CPrincipal::RemovePermission(BOOL bAllow, PPERMISSION pperm)
{
if (bAllow)
m_permAllow.RemovePermission(pperm);
else
m_permDeny.RemovePermission(pperm);
}
//
// CPermPage implementation
//
void
CPermPage::InitPrincipalList(HWND hDlg, PACL pDacl)
{
TraceEnter(TRACE_PERMPAGE, "CPermPage::InitPrincipalList");
TraceAssert(hDlg != NULL);
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
TraceAssert(hwndList != NULL);
// Save the DACL revision
if (pDacl != NULL)
{
m_wDaclRevision = pDacl->AclRevision;
}
// If we have a selection, remember the SID for later
PSID psidTemp = NULL;
LPPRINCIPAL pPrincipal = (LPPRINCIPAL)GetSelectedItemData(hwndList, NULL);
if (pPrincipal != NULL)
psidTemp = LocalAllocSid(pPrincipal->GetSID());
// Empty out the list
ListView_DeleteAllItems(hwndList);
// Enumerate the new DACL and fill the list
EnumerateAcl(hwndList, pDacl);
// Try to re-select the previously selection
if (psidTemp != NULL)
{
int cItems = ListView_GetItemCount(hwndList);
LV_ITEM lvItem;
lvItem.iSubItem = 0;
lvItem.mask = LVIF_PARAM;
// Look for the previously selected principal in the list
while (cItems > 0)
{
--cItems;
lvItem.iItem = cItems;
ListView_GetItem(hwndList, &lvItem);
pPrincipal = (LPPRINCIPAL)lvItem.lParam;
if (EqualSid(psidTemp, pPrincipal->GetSID()))
{
SelectListViewItem(hwndList, cItems);
break;
}
}
LocalFree(psidTemp);
}
TraceLeaveVoid();
}
STDMETHODIMP
_InitCheckList(HWND hwndList,
LPSECURITYINFO psi,
const GUID* pguidObjectType,
DWORD dwFlags,
HINSTANCE hInstance,
DWORD dwType,
PSI_ACCESS *ppDefaultAccess)
{
HRESULT hr;
PSI_ACCESS pAccess;
ULONG cAccesses;
ULONG iDefaultAccess;
TCHAR szName[MAX_PATH];
TraceEnter(TRACE_MISC, "_InitCheckList");
TraceAssert(psi != NULL);
//
// Retrieve the permission list
//
hr = psi->GetAccessRights(pguidObjectType,
dwFlags,
&pAccess,
&cAccesses,
&iDefaultAccess);
if (SUCCEEDED(hr) && cAccesses > 0)
{
if (ppDefaultAccess != NULL)
*ppDefaultAccess = &pAccess[iDefaultAccess];
// Enumerate the permissions and add to the checklist
for (ULONG i = 0; i < cAccesses; i++, pAccess++)
{
LPCTSTR pszName;
// Only add permissions that have any of the flags specified in dwType
if (!(pAccess->dwFlags & dwType))
continue;
pszName = pAccess->pszName;
if (IS_INTRESOURCE(pszName))
{
TraceAssert(hInstance != NULL);
if (LoadString(hInstance,
(UINT)((ULONG_PTR)pszName),
szName,
ARRAYSIZE(szName)) == 0)
{
LoadString(::hModule,
IDS_UNKNOWN,
szName,
ARRAYSIZE(szName));
}
pszName = szName;
}
if (SendMessage(hwndList,
CLM_ADDITEM,
(WPARAM)pszName,
(LPARAM)pAccess) == -1)
{
DWORD dwErr = GetLastError();
ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Failed to add item to checklist");
}
}
}
exit_gracefully:
TraceLeaveResult(hr);
}
HRESULT
CPermPage::InitCheckList(HWND hDlg)
{
HRESULT hr;
TCHAR szName[MAX_PATH];
PSI_ACCESS pAccess;
TraceEnter(TRACE_PERMPAGE, "CPermPage::InitCheckList");
TraceAssert(hDlg != NULL);
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PERMS); // checklist window
TraceAssert(hwndList != NULL);
DWORD dwType = SI_ACCESS_GENERAL;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
dwType |= SI_ACCESS_CONTAINER;
// Enumerate the permissions and add to the checklist
hr = _InitCheckList(hwndList,
m_psi,
NULL,
0,
m_siObjectInfo.hInstance,
dwType,
&m_pDefaultAccess);
if (SUCCEEDED(hr))
{
//Add Custom Checkbox at the bottom of checklist. Custom checkbox is added only if
//Advanced Page is there
if(m_bCustomPermission)
{
if( ( pAccess = (PSI_ACCESS)LocalAlloc( LPTR, sizeof( SI_ACCESS ) ) ) == NULL )
ExitGracefully(hr, HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY), "Failed to allocate Memeory");
pAccess->dwFlags = SI_ACCESS_CUSTOM;
LoadString(::hModule, IDS_CUSTOM, szName, ARRAYSIZE(szName));
if (SendMessage(hwndList, CLM_ADDITEM, (WPARAM)szName, (LPARAM)pAccess) == -1)
{
DWORD dwErr = GetLastError();
ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Failed to add item to checklist");
}
//
//Disable the custom checkbox
//
ClearCustom(hwndList,1);
ClearCustom(hwndList,2);
}
}
exit_gracefully:
TraceLeaveResult(hr);
}
//
// CAUTION - This function modifies the ACEs in the ACL by setting
// the AceType to 0xff (an invalid ACE type).
//
//This function goes through the ACL and groups the aces
//according to SID in PRINCIPAL objects.
void
CPermPage::EnumerateAcl(HWND hwndList, PACL pAcl)
{
LPPRINCIPAL pPrincipal;
PACE_HEADER pAce;
int iEntry;
int iTemp;
PACE_HEADER paceTemp;
HDPA hSids = NULL;
if (pAcl == NULL)
return;
TraceEnter(TRACE_PERMPAGE, "CPermPage::EnumerateAcl");
TraceAssert(IsValidAcl(pAcl));
TraceAssert(hwndList != NULL);
hSids = DPA_Create(4);
if (NULL == hSids)
TraceLeaveVoid();
for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
iEntry < pAcl->AceCount;
iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
{
// Skip ACEs that we've already seen
if (pAce->AceType == 0xff)
continue;
// Found an ACE we haven't seen yet, must be a new principal
pPrincipal = new CPrincipal(this);
if (pPrincipal == NULL)
continue; // memory error (try to continue)
// Initialize new principal
if (!pPrincipal->SetPrincipal(GetAceSid(pAce)))
{
delete pPrincipal;
continue; // probably memory error (try to continue)
}
// Remember the SIDs so that later we can look up all the names
// at once and then add them to the listview.
DPA_AppendPtr(hSids, pPrincipal->GetSID());
// The current ACE belongs to this principal, so add it
pPrincipal->AddAce(pAce);
// Mark the ACE so we don't look at it again
pAce->AceType = 0xff;
// Loop through the rest of the ACEs in the ACL looking
// for the same SID
paceTemp = pAce;
for (iTemp = iEntry + 1; iTemp < pAcl->AceCount; iTemp++)
{
// Move pointer to the current ACE
paceTemp = (PACE_HEADER)NextAce(paceTemp);
// If this ACE belongs to the current principal, add it
if (paceTemp->AceType != 0xff &&
EqualSid(GetAceSid(paceTemp), pPrincipal->GetSID()))
{
// Same principal, add the ACE
pPrincipal->AddAce(paceTemp);
// Mark the ACE so we don't look at it again
paceTemp->AceType = 0xff;
}
}
if (-1 == AddPrincipalToList(hwndList, pPrincipal))
{
delete pPrincipal;
}
}
// Launch thread to look up sids
m_fBusy = TRUE;
LookupSidsAsync(hSids,
m_siObjectInfo.pszServerName,
m_psi2,
GetParent(hwndList),
UM_SIDLOOKUPCOMPLETE);
DPA_Destroy(hSids);
TraceLeaveVoid();
}
HRESULT
CPermPage::SetPrincipalNamesInList(HWND hwndList, PSID pSid)
{
TraceEnter(TRACE_PERMPAGE, "CPermPage::SetPrincipalNamesInList");
HRESULT hr = S_OK;
PUSER_LIST pUserList = NULL;
LPPRINCIPAL pPrincipal = NULL;
LVITEM lvItem = {0};
int cListItems;
int iListItem;
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Enumerate through each entry in the list view
cListItems = ListView_GetItemCount(hwndList);
for (iListItem = 0; iListItem < cListItems; iListItem++)
{
lvItem.mask = LVIF_PARAM;
lvItem.iItem = iListItem;
lvItem.iSubItem = 0;
if (ListView_GetItem(hwndList, &lvItem))
{
pPrincipal = (LPPRINCIPAL) lvItem.lParam;
if (pPrincipal != NULL)
{
// Are we looking for a particular principal?
if (pSid && !EqualSid(pSid, pPrincipal->GetSID()))
continue;
// Do we already have a good name?
if (pPrincipal->HaveRealName())
{
if (pSid)
break; // only care about this principal, stop here
else
continue; // skip this one and check the rest
}
// Lookup the SID for this principal in the cache
LookupSid(pPrincipal->GetSID(),
m_siObjectInfo.pszServerName,
m_psi2,
&pUserList);
if ((pUserList != NULL) && (pUserList->cUsers == 1))
{
// The list should contain a single item
PUSER_INFO pUserInfo = &pUserList->rgUsers[0];
// Update the principal with this new name information
pPrincipal->SetSidType(pUserInfo->SidType);
pPrincipal->SetName(pUserInfo->pszName, pUserInfo->pszLogonName);
// Set the text of this item to the name we've found
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
lvItem.pszText = (LPTSTR)pPrincipal->GetName();
lvItem.iImage = pPrincipal->GetImageIndex();
ListView_SetItem(hwndList, &lvItem);
LocalFree(pUserList);
}
}
}
}
SetCursor(hcur);
TraceLeaveResult(hr);
}
int
CPermPage::AddPrincipalToList(HWND hwndList, LPPRINCIPAL pPrincipal)
{
LVITEM lvItem;
int iIndex = -1;
TraceEnter(TRACE_PERMPAGE, "CPermPage::AddPrincipalToList");
TraceAssert(hwndList != NULL);
TraceAssert(pPrincipal != NULL);
// Insert new principal into listview
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.lParam = (LPARAM)pPrincipal;
lvItem.pszText = (LPTSTR)pPrincipal->GetName();
lvItem.iImage = pPrincipal->GetImageIndex();
iIndex = ListView_InsertItem(hwndList, &lvItem);
TraceLeaveValue(iIndex);
}
VOID
CPermPage::SetPermLabelText(HWND hDlg)
{
RECT rc;
WCHAR szBuffer[MAX_COLUMN_CHARS];
HWND hwndLabel;
HWND hwndList;
LPTSTR pszCaption = NULL;
SIZE size;
LPCWSTR pszUserName = NULL;
CPrincipal * pPrincipal = NULL;
int iIndex = 0;
//Get Label Dimension
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS);
GetClientRect(hwndLabel, &rc);
MapDialogRect(hDlg,&rc);
//Get Text Dimension
HDC hdc = GetDC(hDlg);
hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
pPrincipal = (LPPRINCIPAL)GetSelectedItemData(hwndList, &iIndex);
if(pPrincipal)
pszUserName = pPrincipal->GetDisplayName();
if(pszUserName)
FormatStringID(&pszCaption, ::hModule, IDS_DYNAMIC_PERMISSION,pszUserName);
else
FormatStringID(&pszCaption, ::hModule, IDS_PERMISSIONS, NULL);
GetTextExtentPoint32(hdc,pszCaption,wcslen(pszCaption),&size);
if(size.cx > rc.right)
{
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS);
EnableWindow(hwndLabel, FALSE);
ShowWindow(hwndLabel,SW_HIDE);
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS_BIG);
EnableWindow(hwndLabel, TRUE);
ShowWindow(hwndLabel,SW_SHOW);
SetWindowText(hwndLabel,pszCaption);
}
else
{
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS_BIG);
EnableWindow(hwndLabel, FALSE);
ShowWindow(hwndLabel,SW_HIDE);
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS);
EnableWindow(hwndLabel, TRUE);
ShowWindow(hwndLabel,SW_SHOW);
SetWindowText(hwndLabel,pszCaption);
}
hwndLabel = GetDlgItem(hDlg, IDC_EDIT1);
SetWindowText(hwndLabel,pszCaption);
LocalFreeString(&pszCaption);
ReleaseDC(hDlg, hdc);
}
BOOL
CPermPage::InitDlg(HWND hDlg)
{
HRESULT hr = S_OK;
HWND hwnd;
HWND hwndList;
RECT rc;
LV_COLUMN col;
TCHAR szBuffer[MAX_COLUMN_CHARS];
PSECURITY_DESCRIPTOR pSD = NULL;
BOOL bUserNotified = FALSE;
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
TraceEnter(TRACE_PERMPAGE, "CPermPage::InitDlg");
TraceAssert(hDlg != NULL);
TraceAssert(m_psi != NULL);
hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
//
// Create & set the image list for the listview. If there is a
// problem CreateSidImageList will return NULL which won't hurt
// anything. In that case we'll just continue without an image list.
//
ListView_SetImageList(hwndList,
LoadImageList(::hModule, MAKEINTRESOURCE(IDB_SID_ICONS)),
LVSIL_SMALL);
// Set extended LV style for whole line selection with InfoTips
ListView_SetExtendedListViewStyleEx(hwndList,
LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
//
// Add appropriate listview columns
//
GetClientRect(hwndList, &rc);
col.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH;
col.fmt = LVCFMT_LEFT;
col.iSubItem = 0;
col.cx = rc.right;
ListView_InsertColumn(hwndList, 0, &col);
if (!(m_siObjectInfo.dwFlags & SI_ADVANCED))
{
// Hide the Advanced button
hwnd = GetDlgItem(hDlg, IDC_SPP_ADVANCED);
ShowWindow(hwnd, SW_HIDE);
EnableWindow(hwnd, FALSE);
hwnd = GetDlgItem(hDlg, IDC_SPP_STATIC_ADV);
ShowWindow(hwnd, SW_HIDE);
EnableWindow(hwnd, FALSE);
}
if (S_FALSE == m_hrLastPSPCallbackResult)
{
// The propsheetpage callback told us to not show any messages here.
bUserNotified = TRUE;
}
//Additional Permissions?
m_bCustomPermission = (m_siObjectInfo.dwFlags & SI_ADVANCED)
&& !(m_siObjectInfo.dwFlags & SI_NO_ADDITIONAL_PERMISSION);
if (m_bAbortPage)
{
// Disable everything except the Advanced button
m_siObjectInfo.dwFlags |= SI_READONLY;
EnableWindow(hwndList, FALSE);
// The user should have been notified during the propsheetpage
// callback, so don't put up another message now.
bUserNotified = TRUE;
}
else
{
//
// Initialize the checklist window
//
hr = InitCheckList(hDlg);
FailGracefully(hr, "Failed to initialize checklist");
//
// Retrieve the DACL from the object and set it into the dialog
//
hr = m_psi->GetSecurity(DACL_SECURITY_INFORMATION, &pSD, FALSE);
if (SUCCEEDED(hr))
{
// We always disable the advanced button until the SID name cache
// is filled on our other thread. See the DlgProc handler for
// UM_SIDLOOKUPCOMPLETE
EnableWindow(GetDlgItem(hDlg, IDC_SPP_ADVANCED), FALSE);
hr = SetDacl(hDlg, pSD);
FailGracefully(hr, "SetDacl failed");
}
else if (hr == E_ACCESSDENIED)
{
if (!bUserNotified)
{
//
// Can't read the DACL or Owner, figure out what we CAN do.
//
UINT idMsg = IDS_PERM_NO_ACCESS;
UINT mbType = MB_OK | MB_ICONWARNING;
if (!(m_siObjectInfo.dwFlags & SI_READONLY))
{
if(!( m_siObjectInfo.dwFlags & SI_MAY_WRITE))
idMsg = IDS_PERM_CANT_READ_CAN_WRITE_DACL;
else
idMsg = IDS_PERM_CANT_READ_MAY_WRITE_DACL;
}
else
{
//
// Can't write the DACL, can we write the owner or edit the SACL?
//
DWORD dwFlags = m_siObjectInfo.dwFlags & (SI_EDIT_AUDITS | SI_OWNER_READONLY);
// If we're not editing the owner, then we can't write it.
if (!(m_siObjectInfo.dwFlags & SI_EDIT_OWNER))
dwFlags |= SI_OWNER_READONLY;
switch(dwFlags)
{
case 0:
// Can write the Owner but can't edit the SACL
idMsg = IDS_PERM_CANT_READ_CAN_WRITE_OWNER;
break;
case SI_EDIT_AUDITS:
// Can edit the SACL and write the Owner
idMsg = IDS_PERM_CANT_READ_CAN_AUDIT_WRITE_OWNER;
break;
case SI_OWNER_READONLY:
// No Access
break;
case SI_OWNER_READONLY | SI_EDIT_AUDITS:
// Can edit the SACL but can't write the Owner
idMsg = IDS_PERM_CANT_READ_CAN_AUDIT;
break;
}
}
if (idMsg == IDS_PERM_NO_ACCESS)
mbType = MB_OK | MB_ICONERROR;
MsgPopup(hDlg,
MAKEINTRESOURCE(idMsg),
MAKEINTRESOURCE(IDS_SECURITY),
mbType,
::hModule,
m_siObjectInfo.pszObjectName);
bUserNotified = TRUE;
}
EnablePrincipalControls(hDlg, FALSE);
hr = S_OK;
}
else
{
FailGracefully(hr, "GetSecurity failed");
}
} // !m_bAbortPage
if (m_siObjectInfo.dwFlags & SI_READONLY)
{
EnableWindow(GetDlgItem(hDlg, IDC_SPP_ADD), FALSE);
EnablePrincipalControls(hDlg, FALSE);
// Tell the user that we're in read-only mode
//Do not show this dialog box
//Windows Bug 181665
/*if (!bUserNotified)
{
MsgPopup(hDlg,
MAKEINTRESOURCE(IDS_PERM_READONLY),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONINFORMATION,
::hModule,
m_siObjectInfo.pszObjectName);
bUserNotified = TRUE;
}
*/
}
exit_gracefully:
if (pSD != NULL)
LocalFree(pSD);
SetCursor(hcur);
if (FAILED(hr))
{
// Hide and disable everything
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_NO_SECURITY);
EnableWindow(hwnd, TRUE);
ShowWindow(hwnd, SW_SHOW);
}
TraceLeaveValue(TRUE);
}
BOOL
CPermPage::OnNotify(HWND hDlg, int /*idCtrl*/, LPNMHDR pnmh)
{
LPNM_LISTVIEW pnmlv = (LPNM_LISTVIEW)pnmh;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnNotify");
TraceAssert(hDlg != NULL);
TraceAssert(pnmh != NULL);
// Set default return value
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
switch (pnmh->code)
{
case LVN_ITEMCHANGED:
if (pnmlv->uChanged & LVIF_STATE)
{
OnSelChange(hDlg);
// item *gaining* selection
if ((pnmlv->uNewState & LVIS_SELECTED) &&
!(pnmlv->uOldState & LVIS_SELECTED))
{
//here bClearCustom should be False. We don't need to clear
//Custom when we select another principal.
//Build Additional List for it.
}
// item *losing* selection
else if (!(pnmlv->uNewState & LVIS_SELECTED) &&
(pnmlv->uOldState & LVIS_SELECTED))
{
// Post ourselves a message to check for a new selection later.
// If we haven't gotten a new selection by the time we process
// this message, then assume the user clicked inside the listview
// but not on an item, thus causing the listview to remove the
// selection. In that case, disable the combobox & Remove button.
//
// Do this via WM_COMMAND rather than WM_NOTIFY so we don't
// have to allocate/free a NMHDR structure.
PostMessage(hDlg,
WM_COMMAND,
GET_WM_COMMAND_MPS(pnmh->idFrom, pnmh->hwndFrom, IDN_CHECKSELECTION));
}
}
break;
case LVN_DELETEITEM:
delete (LPPRINCIPAL)pnmlv->lParam;
break;
case LVN_KEYDOWN:
if (((LPNMLVKEYDOWN)pnmh)->wVKey == VK_DELETE)
{
//Get the status of Remove button. Only if remove is
//enabled do something bug 390243
if( IsWindowEnabled( GetDlgItem( hDlg,IDC_SPP_REMOVE )) )
OnRemovePrincipal(hDlg);
}
break;
#ifdef UNUSED
case NM_DBLCLK:
if (pnmh->idFrom == IDC_SPP_PRINCIPALS)
{
// Must have a selection to get here
TraceAssert(ListView_GetSelectedCount(pnmh->hwndFrom) == 1);
// do something here
}
break;
#endif
case CLN_CLICK:
if (pnmh->idFrom == IDC_SPP_PERMS)
{
LPPRINCIPAL pPrincipal;
int iIndex = -1;
pPrincipal = (LPPRINCIPAL)GetSelectedItemData(GetDlgItem(hDlg, IDC_SPP_PRINCIPALS), &iIndex);
if (pPrincipal)
{
PNM_CHECKLIST pnmc = (PNM_CHECKLIST)pnmh;
PSI_ACCESS pAccess = (PSI_ACCESS)pnmc->dwItemData;
//Custom checkbox is clicked, reqiures special handling
if( pAccess->dwFlags & SI_ACCESS_CUSTOM )
{
if (pnmc->dwState & CLST_CHECKED)
{
//Uncheck the Checkbox. Can checkbox be prevented from checked?
SendMessage(pnmc->hdr.hwndFrom,
CLM_SETSTATE,
MAKELONG((WORD)pnmc->iItem, (WORD)pnmc->iSubItem),
0
);
//Show the message box
MsgPopup(hDlg,
MAKEINTRESOURCE(IDS_CUSTOM_CHECKBOX_WARNING),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONINFORMATION,
::hModule);
}
else
{
SetDirty(hDlg);
//Clear the Special Checkbox and Permissions
BOOL bClearAllow = (1 == pnmc->iSubItem); // 1 = Allow, 2 = Deny
OnSelChange(hDlg, TRUE, bClearAllow, !bClearAllow);
}
//Break out of Switch
break;
}
}
//
// HandleListClick decides which boxes should be checked and
// unchecked, however, we can't rely only on that to generate
// ACLs (we used to). Suppose the principal has Full Control and
// the user unchecks "Delete" which is a single bit. If there is
// no checkbox corresponding to "Full Control minus Delete" then
// the principal would also lose other bits, such as WRITE_DAC.
//
// So let HandleListClick do its thing. Then remove permission
// bits according to what was checked or unchecked.
//
// But wait, there's more. Removing permission bits turns off
// too much. For example, if the principal has Full Control and
// the user turns off Full Control, then the principal ends up
// with nothing, even though HandleListClick leaves Modify
// checked.
//
// So after removing what was just (un)checked, build new
// permissions from what is still checked and add them.
//
// This yields the correct results, and also keeps the principal
// up-to-date so we don't need to call CommitCurrent anywhere else.
//
// Raid 260952
//
//HandleListClick decides which boxes should be checked and unchecked.
//If FullControl was intially Checked, we uncheck Read, Full Control is
//also unchecked. If a checkbox was intially checked and unchecked in
//HandleListClick, its added to h[Allow/Deny]UncheckedAccess list.
//Permission corresponding to these checkboxes is removed.
// Check/uncheck appropriate boxes in both columns
HDSA hAllowUncheckedAccess = NULL;
HDSA hDenyUncheckedAccess = NULL;
//Does appropriate check-uncheck.
HandleListClick((PNM_CHECKLIST)pnmh,
SI_PAGE_PERM,
m_siObjectInfo.dwFlags & SI_CONTAINER,
&hAllowUncheckedAccess,
&hDenyUncheckedAccess,
m_bCustomPermission);
pPrincipal = (LPPRINCIPAL)GetSelectedItemData(GetDlgItem(hDlg, IDC_SPP_PRINCIPALS), &iIndex);
if (pPrincipal)
{
PNM_CHECKLIST pnmc = (PNM_CHECKLIST)pnmh;
PSI_ACCESS pAccess = (PSI_ACCESS)pnmc->dwItemData;
PERMISSION perm = { pAccess->mask, 0, 0 };
//If we uncheck Allow Read, Allow Read Checkbox goes into HandleListClick as
//unchecked and is not in hAllowUncheckedAccess. Perm Corresponding to it
//especially removed.
if(!(pnmc->dwState & CLST_CHECKED))
{
// Which column was clicked?
BOOL bRemoveFromAllow = (1 == pnmc->iSubItem); // 1 = Allow, 2 = Deny
if (pAccess->pguid)
perm.guid = *pAccess->pguid;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
perm.dwFlags = pAccess->dwFlags & VALID_INHERIT_FLAGS;
pPrincipal->RemovePermission(bRemoveFromAllow, &perm);
}
if( hAllowUncheckedAccess )
{
UINT cItems = DSA_GetItemCount(hAllowUncheckedAccess);
PERMISSION permTemp;
while (cItems)
{
--cItems;
DSA_GetItem(hAllowUncheckedAccess, cItems, &pAccess);
permTemp.mask = pAccess->mask;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
permTemp.dwFlags = pAccess->dwFlags & VALID_INHERIT_FLAGS;
if( pAccess->pguid )
permTemp.guid = *pAccess->pguid;
pPrincipal->RemovePermission(TRUE, &permTemp);
}
DSA_Destroy(hAllowUncheckedAccess);
}
if( hDenyUncheckedAccess )
{
UINT cItems = DSA_GetItemCount(hDenyUncheckedAccess);
PERMISSION permTemp;
PSI_ACCESS pAccess2 = NULL;
while (cItems)
{
--cItems;
DSA_GetItem(hDenyUncheckedAccess, cItems, &pAccess2);
permTemp.mask = pAccess2->mask;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
permTemp.dwFlags = pAccess2->dwFlags & VALID_INHERIT_FLAGS;
if( pAccess2->pguid )
permTemp.guid = *pAccess2->pguid;
pPrincipal->RemovePermission(FALSE, &permTemp);
}
DSA_Destroy(hDenyUncheckedAccess);
}
}
SetDirty(hDlg);
// Add perms according to what is still checked. This is required, since
// when i uncheck Read, full control is also unchecked and permission corresponding to
// it is removed. This will remove Write also, though its still checked.
//CommitCurrent will add permission for checkboxes which are still checked.
CommitCurrent(hDlg, iIndex);
//Here i should add additional list to main list, but no need to rebuild addtional list
// Reset the "There is more stuff" message
OnSelChange(hDlg, FALSE);
}
break;
case CLN_GETCOLUMNDESC:
{
PNM_CHECKLIST pnmc = (PNM_CHECKLIST)pnmh;
GetDlgItemText(hDlg,
IDC_SPP_ALLOW - 1 + pnmc->iSubItem,
pnmc->pszText,
pnmc->cchTextMax);
}
break;
case PSN_APPLY:
OnApply(hDlg, (BOOL)(((LPPSHNOTIFY)pnmh)->lParam));
break;
default:
TraceLeaveValue(FALSE); // message not handled
}
TraceLeaveValue(TRUE); // message handled
}
BOOL
CheckPermissions(HWND hwndList,
CPermissionSet &PermSet,
WORD wColumn,
BOOL bDisabled,
BOOL bInheritFlags,
BOOL bCustom, //Does Custom Checkbox exist?
BOOL bClearCustom,
HDSA hAdditional )//Clear Custom Permissions?
{
UINT cRights = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
//Custom Checkbox is handled separately the end.
if( bCustom )
--cRights;
UINT cAces = PermSet.GetPermCount();
BOOL bMorePresent = FALSE;
WORD wOtherColumn;
DWORD dwState = CLST_CHECKED;
TraceEnter(TRACE_MISC, "CheckPermissions");
HDSA hPermList; //Temp List of PPERMISSION pointers
if( bClearCustom )
{
hPermList = DSA_Create(SIZEOF(PPERMISSION), 4);
if (hPermList == NULL)
{
TraceMsg("DSA_Create failed");
TraceLeaveValue(FALSE);
}
}
if (wColumn == 1)
wOtherColumn = 2;
else
wOtherColumn = 1;
if (bDisabled)
dwState |= CLST_DISABLED;
for (UINT j = 0; j < cAces; j++)
{
ACCESS_MASK maskChecked = 0;
PPERMISSION pPerm = PermSet[j];
BOOL bIsNullGuid = IsNullGUID(&pPerm->guid);
//Igonre custom here
for (UINT i = 0; i < cRights ; i++)
{
PSI_ACCESS pAccess = (PSI_ACCESS)SendMessage(hwndList,
CLM_GETITEMDATA,
i,
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[i].mask then
// it effectively has that option enabled.
//
if ( (pPerm->mask & pAccess->mask) == pAccess->mask &&
(bIsNullGuid || IsSameGUID(&pPerm->guid, pAccess->pguid)) )
{
DWORD dwStateCompare;
//
// Next, check the inherit flags.
//
if (bInheritFlags)
{
DWORD dwCommonFlags = pPerm->dwFlags & pAccess->dwFlags;
//
// This expression tests to see whether the ACE applies
// to all objects that this access rights line applies to.
// The ACE must have at least as many of (CONTAINER_INHERIT_ACE,
// OBJECT_INHERIT_ACE) turned on as the rights line, and
// if the ACE has INHERIT_ONLY_ACE, then so must the rights line.
//
if (!((dwCommonFlags & ACE_INHERIT_ALL) == (pAccess->dwFlags & ACE_INHERIT_ALL)
&& (dwCommonFlags & INHERIT_ONLY_ACE) == (pPerm->dwFlags & INHERIT_ONLY_ACE)))
continue;
}
// The bits say it's checked. We may not actually check the box
// below, but for other reasons. In any case, we don't want the
// "Additional stuff is here but I can't show it" message to
// display because of this perm.
maskChecked |= pAccess->mask;
//
// Ok, the bits say that this box should be checked, but
// if the other column is already checked and has the same
// enabled/disabled state, then we don't check this one.
// This keeps us from having both Allow and Deny checked &
// enabled on the same line (nonsense) or checked & disabled
// on the same line (both inherited; we must show both as
// Allow Inherited can preceede Deny Inherited and we
// don't know the order at this point.
//
if( !(pPerm->dwFlags & INHERITED_ACE) )
{
dwStateCompare = (DWORD)SendMessage(hwndList,
CLM_GETSTATE,
MAKELONG((WORD)i, wOtherColumn),
0);
if ((dwStateCompare & CLST_CHECKED) &&
((dwStateCompare & CLST_DISABLED) == (dwState & CLST_DISABLED)))
continue;
}
//
// Next, see if the box is already checked. If so, leave it
// alone. Note that we don't compare the enabled/disabled
// state. The effect here is that the first check wins.
// Raid 326000
//
dwStateCompare = (DWORD)SendMessage(hwndList,
CLM_GETSTATE,
MAKELONG((WORD)i, wColumn),
0);
if (dwStateCompare & CLST_CHECKED)
continue;
//
// Finally, check the box.
//
SendMessage(hwndList,
CLM_SETSTATE,
MAKELONG((WORD)i, wColumn),
dwState);
}
}
if( bClearCustom )
{
//If an ace don't check anyof the checkboxes,( i.e. maskchecked = 0 ),
//it should be removed when custom is unchecked.
if( !maskChecked )
{
DSA_AppendItem(hPermList, &pPerm);
maskChecked = pPerm->mask; //this is done to make sure maskchecked is false
}
//Ace checks some checkbox ( maskChecked), so it mask should be maskChecked
else
pPerm->mask = maskChecked;
}
// Does this ACE have bits that aren't shown on this dialog?
if (maskChecked != pPerm->mask)
{
ACCESS_MASK maskTemp = 0;
//Add this ace to the list of additional aces,
//but only the bits which are additional
if( hAdditional )
{
maskTemp = pPerm->mask;
pPerm->mask &= ~maskChecked;
DSA_AppendItem(hAdditional, pPerm);
pPerm->mask = maskTemp;
}
bMorePresent = TRUE;
}
}
if( bClearCustom )
{
UINT cItems = DSA_GetItemCount(hPermList);
PPERMISSION pTemp = NULL;
while (cItems)
{
--cItems;
DSA_GetItem(hPermList, cItems, &pTemp);
//Removes only the permission which match its inheritance flag, not others.
//For example it this permission is read applied to subobjects and hence appear as
//custom permission. On clearing the custom checkbox, only read permission applied to
//subobjects should go, not the read permission applied to this object ( and/or subobjects)
// which can be shown in other checkboxes.
PermSet.RemovePermission(pTemp, TRUE);
--cAces;
}
PermSet.ResetAdvanced();
DSA_Destroy(hPermList);
}
// Does this permission set have "advanced" ACEs that aren't shown
// on this dialog?
if (!bMorePresent && cAces != PermSet.GetPermCount(TRUE))
bMorePresent = TRUE;
if( bMorePresent && bCustom )
CheckCustom( hwndList, wColumn, dwState );
TraceLeaveValue(bMorePresent);
}
void
CPermPage::OnSelChange(HWND hDlg, BOOL bClearFirst, BOOL bClearCustomAllow, BOOL bClearCustomDeny)
{
BOOL bDisabled = m_siObjectInfo.dwFlags & SI_READONLY;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnSelChange");
TraceAssert(hDlg != NULL);
//
// If the principal list is empty or there is no selection, then we need
// to disable all of the controls that operate on items in the listbox.
//
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
TraceAssert(hwndList != NULL);
// Get the selected principal
LPPRINCIPAL pPrincipal = (LPPRINCIPAL)GetSelectedItemData(hwndList, NULL);
// Enable/disable the other controls
if (!bDisabled)
EnablePrincipalControls(hDlg, pPrincipal != NULL);
//Change the permission label to reflect the new User/Group
SetPermLabelText(hDlg);
if (pPrincipal == NULL)
TraceLeaveVoid(); // no selection or empty list
//
// Check/uncheck the permission boxes
//
hwndList = GetDlgItem(hDlg, IDC_SPP_PERMS);
TraceAssert(hwndList != NULL);
if (bClearFirst)
{
// First need to uncheck everything
ClearPermissions(hwndList, bDisabled);
}
BOOL bIsContainer = m_siObjectInfo.dwFlags & SI_CONTAINER;
BOOL bMorePresent = FALSE;
//Clear the Custom Checkboxes. This is the only place where Custom Checkbox is cleared
if(m_bCustomPermission)
{
ClearCustom(hwndList,1);
ClearCustom(hwndList,2);
}
if( !pPrincipal->m_hAdditionalAllow )
{
pPrincipal->m_hAdditionalAllow = DSA_Create(SIZEOF(PERMISSION), 4);
if (pPrincipal->m_hAdditionalAllow == NULL)
{
TraceMsg("DSA_Create failed");
TraceLeaveVoid();
}
}
if( !pPrincipal->m_hAdditionalDeny )
{
pPrincipal->m_hAdditionalDeny = DSA_Create(SIZEOF(PERMISSION), 4);
if (pPrincipal->m_hAdditionalDeny == NULL)
{
TraceMsg("DSA_Create failed");
TraceLeaveVoid();
}
}
UINT cItems = DSA_GetItemCount(pPrincipal->m_hAdditionalAllow);
PPERMISSION pPermTemp;
while (cItems)
{
--cItems;
pPermTemp = (PPERMISSION)DSA_GetItemPtr(pPrincipal->m_hAdditionalAllow, cItems );
if(pPermTemp)
pPrincipal->AddPermission(TRUE, pPermTemp);
}
DSA_DeleteAllItems(pPrincipal->m_hAdditionalAllow);
cItems = DSA_GetItemCount(pPrincipal->m_hAdditionalDeny);
while (cItems)
{
--cItems;
pPermTemp = (PPERMISSION)DSA_GetItemPtr(pPrincipal->m_hAdditionalDeny, cItems );
if(pPermTemp)
pPrincipal->AddPermission(FALSE, pPermTemp);
}
DSA_DeleteAllItems(pPrincipal->m_hAdditionalDeny);
bMorePresent |= CheckPermissions(hwndList,
pPrincipal->m_permDeny,
2,
bDisabled,
bIsContainer,
m_bCustomPermission,
bClearCustomDeny,
pPrincipal->m_hAdditionalDeny);
bMorePresent |= CheckPermissions(hwndList,
pPrincipal->m_permAllow,
1,
bDisabled,
bIsContainer,
m_bCustomPermission,
bClearCustomAllow,
pPrincipal->m_hAdditionalAllow);
bMorePresent |= CheckPermissions(hwndList,
pPrincipal->m_permInheritedDeny,
2,
TRUE,
bIsContainer,
m_bCustomPermission,
FALSE,
NULL);
bMorePresent |= CheckPermissions(hwndList,
pPrincipal->m_permInheritedAllow,
1,
TRUE,
bIsContainer,
m_bCustomPermission,
FALSE,NULL);
if (m_siObjectInfo.dwFlags & SI_ADVANCED)
{
ShowWindow(GetDlgItem(hDlg, IDC_SPP_MORE_MSG),
(bMorePresent ? SW_SHOW : SW_HIDE));
}
else if (bMorePresent)
{
TraceMsg("Ignoring unknown permissions");
}
TraceLeaveVoid();
}
void
CPermPage::OnApply(HWND hDlg, BOOL bClose)
{
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pSD;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnApply");
// Build a new DACL without the inherited ACEs.
if (m_fPageDirty && SUCCEEDED(hr = BuildDacl(hDlg, &pSD, FALSE)) && (hr != S_FALSE))
{
PISECURITY_DESCRIPTOR psd = (PISECURITY_DESCRIPTOR)pSD;
DWORD dwWarning = 0;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
TraceAssert(pSD != NULL);
TraceAssert(m_psi != NULL);
// Check for Deny ACEs in the ACL
if (!m_bWasDenyAcl)
{
DWORD dwFullControl = GENERIC_ALL;
UCHAR aceFlags = 0;
m_psi->MapGeneric(NULL, &aceFlags, &dwFullControl);
if (IsDenyACL(psd->Dacl,
(psd->Control & SE_DACL_PROTECTED),
dwFullControl,
&dwWarning))
{
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))
{
hr = S_FALSE;
}
}
}
if (S_FALSE != hr)
{
if(!IsAclBloated(hDlg, si, pSD, m_cInheritableAces, m_siObjectInfo.dwFlags & SI_EDIT_PROPERTIES))
{
// Apply the new security descriptor on the object
hr = m_psi->SetSecurity(si, pSD);
}
else
hr = S_FALSE;
}
if (S_OK == hr)
{
LocalFree(pSD);
pSD = NULL;
m_fPageDirty = FALSE;
if (!bClose)
{
//
// Read the new DACL back from the object. This ensures that we
// have the "real" current DACL in case it was modified by the
// object. For example, inherited aces may have been added.
//
// This also resets the dialog to the initial state if the
// user chose No in the confirmation dialog above.
//
if (SUCCEEDED(m_psi->GetSecurity(DACL_SECURITY_INFORMATION, &pSD, FALSE)))
SetDacl(hDlg, pSD);
}
}
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);
}
if (pSD != NULL)
LocalFree(pSD);
}
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.
if (IDCANCEL != SysMsgPopup(hDlg,
MAKEINTRESOURCE(IDS_PERM_WRITE_FAILED),
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);
}
}
TraceLeaveVoid();
}
/*-----------------------------------------------------------------------------
/ BuildDacl
/ -------
/ Convert the listbox entries into SD. If the size of security descriptor
/ is more than Max allowed shows a dialog box.
/ ppSD can be NULL for the cases where we want to verify if the SD size is
/ not execeeding the max size.
/
/----------------------------------------------------------------------------*/
HRESULT
CPermPage::BuildDacl(HWND hDlg,
PSECURITY_DESCRIPTOR *ppSD,
BOOL fIncludeInherited)
{
PISECURITY_DESCRIPTOR pSD;
ULONG nAclSize;
LPPRINCIPAL pPrincipal;
int cPrincipals = 0;
DWORD dwFlags;
int i, j;
HCURSOR hcur = NULL;
HWND hwndList = NULL;
LV_ITEM lvItem;
lvItem.mask = LVIF_PARAM;
lvItem.iSubItem = 0;
static DWORD dwCanonicalFlags[] =
{
ACL_DENY | ACL_NONOBJECT,
ACL_DENY | ACL_OBJECT,
ACL_ALLOW | ACL_NONOBJECT,
ACL_ALLOW | ACL_OBJECT
};
TraceEnter(TRACE_PERMPAGE, "CPermPage::BuildDacl");
TraceAssert(hDlg != NULL);
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Estimate the size of the buffer necessary to build the
// Security Descriptor.
//
hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
cPrincipals = ListView_GetItemCount(hwndList);
dwFlags = ACL_NONINHERITED;
if (fIncludeInherited)
dwFlags |= ACL_INHERITED;
WORD nMaxAclSize = 0xffff;
nAclSize = SIZEOF(ACL);
for (i = 0; i < cPrincipals; i++)
{
lvItem.iItem = i;
if (ListView_GetItem(hwndList, &lvItem))
{
pPrincipal = (LPPRINCIPAL)lvItem.lParam;
nAclSize += pPrincipal->GetAclLength(dwFlags);
}
if(nAclSize > nMaxAclSize)
{
//
//itow converts upto 33 bytes so 34bytes is fine
//
WCHAR buffer[34];
_itow((cPrincipals - i),buffer,10);
ULONG nMsgId = IDS_ACL_SIZE_ERROR;
if(!ppSD)
nMsgId = IDS_ACL_SIZE_ERROR_ADV;
MsgPopup(hDlg,
MAKEINTRESOURCE(nMsgId),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONERROR,
::hModule,
buffer);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID);
//
//Do a silent failure since we have already shown the error message
//
return S_FALSE;
}
}
if(!ppSD)
return S_OK;
*ppSD = NULL;
//
// Now that we have the size estimate, allocate the buffer. Note that
// we allocate enough memory for a self-relative security descriptor, but
// don't set the SE_SELF_RELATIVE flag in pSD->Control. This lets us
// use pSD->Dacl, etc. as pointers rather than offsets.
//
*ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH + nAclSize);
if (*ppSD == NULL)
TraceLeaveResult(E_OUTOFMEMORY);
InitializeSecurityDescriptor(*ppSD, SECURITY_DESCRIPTOR_REVISION);
pSD = (PISECURITY_DESCRIPTOR)*ppSD;
//
// Finally, build the security descriptor
//
pSD->Control |= SE_DACL_PRESENT | SE_DACL_AUTO_INHERIT_REQ
| (m_wSDControl & (SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED));
if (nAclSize > 0)
{
pSD->Dacl = (PACL)(pSD + 1);
pSD->Dacl->AclRevision = ACL_REVISION;
pSD->Dacl->AclSize = (WORD)nAclSize;
pSD->Dacl->AceCount = 0;
PACE_HEADER pAcePos = (PACE_HEADER)FirstAce(pSD->Dacl);
DWORD dwExtraFlags = fIncludeInherited ? 0 : ACL_CHECK_CREATOR;
// Build the DACL in the following order:
// Deny
// Allow
// Inherited Deny
// Inherited Allow
for (j = 0; j < ARRAYSIZE(dwCanonicalFlags); j++)
{
for (i = 0; i < cPrincipals; i++)
{
lvItem.iItem = i;
if (ListView_GetItem(hwndList, &lvItem))
{
pPrincipal = (LPPRINCIPAL)lvItem.lParam;
pPrincipal->AppendToAcl(pSD->Dacl,
ACL_NONINHERITED | dwCanonicalFlags[j] | dwExtraFlags,
&pAcePos);
}
}
}
if (fIncludeInherited)
{
for (j = 0; j < ARRAYSIZE(dwCanonicalFlags); j++)
{
for (i = 0; i < cPrincipals; i++)
{
lvItem.iItem = i;
if (ListView_GetItem(hwndList, &lvItem))
{
pPrincipal = (LPPRINCIPAL)lvItem.lParam;
pPrincipal->AppendToAcl(pSD->Dacl,
ACL_INHERITED | dwCanonicalFlags[j] | dwExtraFlags,
&pAcePos);
}
}
}
}
// Set accurate size information for the ACL
nAclSize = (ULONG)((PBYTE)pAcePos - (PBYTE)pSD->Dacl);
TraceAssert(nAclSize >= SIZEOF(ACL));
TraceAssert(pSD->Dacl->AclSize >= nAclSize);
if (pSD->Dacl->AclSize > nAclSize)
pSD->Dacl->AclSize = (WORD)nAclSize;
TraceAssert(m_psi2 || IsDACLCanonical(pSD->Dacl));
}
TraceAssert(pSD && IsValidSecurityDescriptor(pSD));
SetCursor(hcur);
TraceLeaveResult(S_OK);
}
HRESULT
CPermPage::SetDacl(HWND hDlg,
PSECURITY_DESCRIPTOR pSD,
BOOL bDirty)
{
HRESULT hr = S_OK;
PACL pAcl = NULL;
PACL paclAllowAll = NULL;
BOOL bDefaulted;
BOOL bPresent;
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
PSECURITY_DESCRIPTOR pSDDefault = NULL;
DWORD dwRevision;
TraceEnter(TRACE_PERMPAGE, "CPermPage::SetDacl");
TraceAssert(hDlg != NULL);
if (pSD != NULL && !IsValidSecurityDescriptor(pSD))
TraceLeaveResult(E_INVALIDARG);
if (pSD != NULL)
GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
// Save the DACL protection and auto-inherited bits
m_wSDControl &= ~(SE_DACL_DEFAULTED | SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED);
m_wSDControl |= (wSDControl & (SE_DACL_DEFAULTED | SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED));
// Get a pointer to the new DACL
if (pSD != NULL)
GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted);
if (!(m_siObjectInfo.dwFlags & SI_READONLY))
{
// Check for canonical ordering (Deny, Allow, Inherited Deny, Inherited Allow)
if ((m_psi2 && !m_psi2->IsDaclCanonical(pAcl))
|| (!m_psi2 && !IsDACLCanonical(pAcl)))
{
TraceMsg("DACL not in canonical order!");
// Ask the user whether to canonicalize the DACL or
// blow it away completely.
if (IDCANCEL == MsgPopup(hDlg,
MAKEINTRESOURCE(IDS_PERM_NOT_CANONICAL),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OKCANCEL | MB_ICONWARNING,
::hModule,
m_siObjectInfo.pszObjectName))
{
// Blow it away and start over.
pAcl = NULL;
// Does the caller support a default ACL? If so, get it now.
if (m_siObjectInfo.dwFlags & SI_RESET)
{
hr = m_psi->GetSecurity(DACL_SECURITY_INFORMATION,
&pSDDefault,
TRUE);
if (SUCCEEDED(hr) && pSDDefault != NULL)
{
// Save the DACL control bits
GetSecurityDescriptorControl(pSDDefault, &wSDControl, &dwRevision);
m_wSDControl &= ~(SE_DACL_DEFAULTED | SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED);
m_wSDControl |= SE_DACL_DEFAULTED | (wSDControl & (SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED));
// Get a pointer to the new DACL
GetSecurityDescriptorDacl(pSDDefault, &bPresent, &pAcl, &bDefaulted);
}
// else go with a NULL DACL
}
}
// else simply continuing and re-saving will
// cause the DACL to get sorted correctly
// This causes a PropSheet_Changed notification to be sent below
bDirty = TRUE;
}
}
m_bWasDenyAcl = FALSE;
// A NULL ACL implies "Everyone Full control", so
// create such an ACL here
if (pAcl == NULL)
{
PSID psidWorld = QuerySystemSid(UI_SID_World);
DWORD dwSidLength = GetLengthSid(psidWorld);
DWORD dwAclLength = SIZEOF(ACL) + SIZEOF(ACCESS_ALLOWED_ACE)
- SIZEOF(DWORD) + dwSidLength;
m_wDaclRevision = ACL_REVISION;
paclAllowAll = (PACL)LocalAlloc(LPTR, dwAclLength);
if (paclAllowAll != NULL)
{
paclAllowAll->AclRevision = ACL_REVISION;
paclAllowAll->AclSize = (WORD)dwAclLength;
#if 0 //(_WIN32_WINNT >= 0x0500)
paclAllowAll->AceCount = 0;
AddAccessAllowedAceEx(paclAllowAll,
ACL_REVISION,
ACE_INHERIT_ALL,
GENERIC_ALL,
psidWorld);
#else
paclAllowAll->AceCount = 1;
PACE_HEADER pAce = (PACE_HEADER)FirstAce(paclAllowAll);
pAce->AceType = ACCESS_ALLOWED_ACE_TYPE;
pAce->AceFlags = ACE_INHERIT_ALL;
pAce->AceSize = (WORD)dwAclLength - SIZEOF(ACL);
((PACCESS_ALLOWED_ACE)pAce)->Mask = GENERIC_ALL;
CopyMemory(&((PACCESS_ALLOWED_ACE)pAce)->SidStart, psidWorld, dwSidLength);
#endif
pAcl = paclAllowAll;
}
}
else
{
DWORD dwFullControl = GENERIC_ALL;
UCHAR aceFlags = 0;
m_psi->MapGeneric(NULL, &aceFlags, &dwFullControl);
if (IsDenyACL(pAcl,
(m_wSDControl & SE_DACL_PROTECTED),
dwFullControl,
NULL))
{
// Already have Deny ACEs, don't bother warning again later.
m_bWasDenyAcl = TRUE;
}
}
// Reset the list of principals
InitPrincipalList(hDlg, pAcl);
//Get the count of inheritable aces
m_cInheritableAces = GetCountOfInheritableAces(pAcl);
// If there aren't any entries, fake a sel change to update
// (i.e. disable) the other controls.
if (pAcl == NULL || pAcl->AceCount == 0)
OnSelChange(hDlg);
if (bDirty)
SetDirty(hDlg, TRUE);
if (paclAllowAll != NULL)
LocalFree(paclAllowAll);
if (pSDDefault != NULL)
LocalFree(pSDDefault);
TraceLeaveResult(hr);
}
void
CPermPage::OnAddPrincipal(HWND hDlg)
{
PUSER_LIST pUserList = NULL;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnAddPrincipal");
TraceAssert(hDlg != NULL);
if (S_OK == GetUserGroup(hDlg, TRUE, &pUserList))
{
PUSER_INFO pUserInfo;
DWORD i;
BOOL fPageModified = FALSE;
int iItem = -1;
TraceAssert(NULL != pUserList);
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
TraceAssert(hwndList != NULL);
for (i = 0; i < pUserList->cUsers; i++)
{
int cItems;
LV_ITEM lvItem;
LPPRINCIPAL pPrincipal;
BYTE buffer[SIZEOF(KNOWN_OBJECT_ACE) + SIZEOF(GUID)];
PACE_HEADER pAce = (PACE_HEADER)buffer;
pUserInfo = &pUserList->rgUsers[i];
iItem = -1;
// Check whether the new principal is already in our list.
// If so, don't add it again.
cItems = ListView_GetItemCount(hwndList);
lvItem.iSubItem = 0;
lvItem.mask = LVIF_PARAM;
while (cItems > 0)
{
LPPRINCIPAL pPrincipal2 = NULL;
--cItems;
lvItem.iItem = cItems;
ListView_GetItem(hwndList, &lvItem);
pPrincipal2 = (LPPRINCIPAL)lvItem.lParam;
if (EqualSid(pPrincipal2->GetSID(), pUserInfo->pSid))
{
iItem = lvItem.iItem;
break;
}
}
// Did we find it?
if (iItem != -1)
continue;
// ListView_FindItem failed to find a match. Add a
// new principal.
pPrincipal = new CPrincipal(this);
if (!pPrincipal)
continue;
// Initialize principal
if (!pPrincipal->SetPrincipal(pUserInfo->pSid,
pUserInfo->SidType,
pUserInfo->pszName,
pUserInfo->pszLogonName))
{
delete pPrincipal;
continue;
}
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.pszText = (LPTSTR)pPrincipal->GetName();
lvItem.iImage = pPrincipal->GetImageIndex();
lvItem.lParam = (LPARAM)pPrincipal;
// Insert principal into list
iItem = ListView_InsertItem(hwndList, &lvItem);
if (-1 == iItem)
{
delete pPrincipal;
continue;
}
// Add ace with default access
pAce->AceType = ACCESS_ALLOWED_ACE_TYPE;
pAce->AceFlags = 0;
pAce->AceSize = SIZEOF(ACCESS_ALLOWED_ACE);
((PACCESS_ALLOWED_ACE)pAce)->Mask = m_pDefaultAccess->mask;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
{
// Pick up inherit bits from the default access
pAce->AceFlags = (UCHAR)(m_pDefaultAccess->dwFlags & (VALID_INHERIT_FLAGS & ~INHERITED_ACE));
//
// Special case for CreatorOwner/CreatorGroup,
// which are only useful if inherit bits are set.
//
if (IsCreatorSid(pUserInfo->pSid))
{
// Make sure it inherits onto something
if (!(pAce->AceFlags & ACE_INHERIT_ALL))
pAce->AceFlags = ACE_INHERIT_ALL;
// It never applies to the current object
pAce->AceFlags |= INHERIT_ONLY_ACE;
// Set it up so whoever creates an object
// gets full control by default
((PACCESS_ALLOWED_ACE)pAce)->Mask = GENERIC_ALL;
}
}
if (!IsNullGUID(m_pDefaultAccess->pguid))
{
pAce->AceType = ACCESS_ALLOWED_OBJECT_ACE_TYPE;
pAce->AceSize = SIZEOF(KNOWN_OBJECT_ACE) + SIZEOF(GUID);
((PKNOWN_OBJECT_ACE)pAce)->Flags = ACE_OBJECT_TYPE_PRESENT;
*RtlObjectAceObjectType(pAce) = *m_pDefaultAccess->pguid;
}
pPrincipal->AddAce(pAce);
fPageModified = TRUE;
}
// Done with this now
LocalFree(pUserList);
if (fPageModified)
{
// If we've added items, resize the Name column
//ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE);
SetDirty(hDlg);
}
if (iItem != -1)
{
// Select the last one inserted.
SelectListViewItem(hwndList, iItem);
}
}
TraceLeaveVoid();
}
void
CPermPage::OnRemovePrincipal(HWND hDlg)
{
HWND hwndList;
int iIndex;
LPPRINCIPAL pPrincipal;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnRemovePrincipal");
hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
pPrincipal = (LPPRINCIPAL)GetSelectedItemData(hwndList, &iIndex);
if (pPrincipal)
{
BOOL bDirty = FALSE;
if (pPrincipal->GetAclLength(ACL_INHERITED) > 0)
{
// This principal has inherited ACEs so we can't remove the principal
// from the list. Instead, simply remove the non-inherited ACEs from
// the principal.
if (pPrincipal->GetAclLength(ACL_NONINHERITED) > 0)
{
pPrincipal->m_permDeny.Reset();
pPrincipal->m_permAllow.Reset();
DSA_DeleteAllItems(pPrincipal->m_hAdditionalAllow);
DSA_DeleteAllItems(pPrincipal->m_hAdditionalDeny);
bDirty = TRUE;
// Update the other controls (this happens automatically in the
// ListView_DeleteItem case below).
OnSelChange(hDlg);
}
else
{
// Notify the user that we can't remove inherited ACEs.
MsgPopup(hDlg,
MAKEINTRESOURCE(IDS_PERM_CANT_REMOVE),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONWARNING,
::hModule,
pPrincipal->GetName());
}
}
else
{
ListView_DeleteItem(hwndList, iIndex);
//
// If we just removed the only item, move the focus to the Add button
// (the Remove button will be disabled in OnSelChange).
//
int cItems = ListView_GetItemCount(hwndList);
if (cItems == 0)
SetFocus(GetDlgItem(hDlg, IDC_SPP_ADD));
else
{
// If we deleted the last one, select the previous one
if (cItems <= iIndex)
--iIndex;
SelectListViewItem(hwndList, iIndex);
//
//Key board focus is getting lost at this point
//set it to REMOVE button.
//
SetFocus(GetDlgItem(hDlg, IDC_SPP_REMOVE));
}
bDirty = TRUE;
}
// Notify the property sheet that we've changed
if (bDirty)
SetDirty(hDlg);
}
TraceLeaveVoid();
}
void
CPermPage::OnAdvanced(HWND hDlg)
{
LPSECURITYINFO psi;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnAdvanced");
//
//Don't go to Advanced page, if DACL size is more than
//maximum allowed.
//
if (m_fPageDirty && (S_FALSE == BuildDacl(hDlg, NULL, FALSE)))
TraceLeaveVoid();
//
// Create an ISecurityInformation wrapper to give to the advanced
// dialog. The wrapper intercepts GetSecurity & SetSecurity.
//
psi = new CSecurityInfo(this, hDlg);
if (psi != NULL)
{
// Invoke the advanced ACL editor
EditSecurityEx(hDlg, psi,this, 0);
psi->Release(); // release initial reference
}
else
{
MsgPopup(hDlg,
MAKEINTRESOURCE(IDS_OUT_OF_MEMORY),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONERROR,
::hModule);
}
TraceLeaveVoid();
}
void
CPermPage::EnablePrincipalControls(HWND hDlg, BOOL fEnable)
{
TraceEnter(TRACE_PERMPAGE, "CPermPage::EnablePrincipalControls");
EnableWindow(GetDlgItem(hDlg, IDC_SPP_PERMS), fEnable);
if (!fEnable)
{
ShowWindow(GetDlgItem(hDlg, IDC_SPP_MORE_MSG), SW_HIDE);
}
else
{
#if 0
LPPRINCIPAL pPrincipal
= (LPPRINCIPAL)GetSelectedItemData(GetDlgItem(hDlg, IDC_SPP_PRINCIPALS),
NULL);
// If the selected principal has only inherited ACEs, then disable
// the Remove button.
if (pPrincipal &&
pPrincipal->GetAclLength(ACL_INHERITED) > 0 &&
pPrincipal->GetAclLength(ACL_NONINHERITED) == 0)
{
fEnable = FALSE;
}
#endif
}
EnableWindow(GetDlgItem(hDlg, IDC_SPP_REMOVE), fEnable);
TraceLeaveVoid();
}
void
CPermPage::CommitCurrent(HWND hDlg, int iPrincipal)
{
// Commit any outstanding bit changes
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
TraceEnter(TRACE_PERMPAGE, "CPermPage::CommitCurrent");
// If an index isn't provided, get the index of the currently
// selected principal.
if (iPrincipal == -1)
iPrincipal = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
if (iPrincipal != -1)
{
// Get the Principal from the selection.
LV_ITEM lvItem;
lvItem.mask = LVIF_PARAM;
lvItem.iItem = iPrincipal;
lvItem.iSubItem = 0;
lvItem.lParam = 0;
ListView_GetItem(hwndList, &lvItem);
LPPRINCIPAL pPrincipal = (LPPRINCIPAL)lvItem.lParam;
if (pPrincipal != NULL)
{
// Get new ACEs from the checklist window
HDPA hAceEntries = DPA_Create(4);
if (hAceEntries != NULL)
{
hwndList = GetDlgItem(hDlg, IDC_SPP_PERMS);
UINT iCount = GetAcesFromCheckList(hwndList,
pPrincipal->GetSID(),
TRUE,
FALSE,
0,
&GUID_NULL,
hAceEntries);
// Merge new ACEs into the principal
while (iCount != 0)
{
--iCount;
PACE_HEADER pAce = (PACE_HEADER)DPA_FastGetPtr(hAceEntries, iCount);
// Shouldn't get any inherited ACEs here
TraceAssert(!(pAce->AceFlags & INHERITED_ACE));
pPrincipal->AddAce(pAce);
LocalFree(pAce);
DPA_DeletePtr(hAceEntries, iCount);
}
TraceAssert(DPA_GetPtrCount(hAceEntries) == 0);
DPA_Destroy(hAceEntries);
}
}
}
TraceLeaveVoid();
}
void
CPermPage::OnSize(HWND hDlg, DWORD dwSizeType, ULONG /*nWidth*/, ULONG /*nHeight*/)
{
RECT rc;
RECT rcDlg;
LONG dx;
LONG dy;
HWND hwndAdvButton;
HWND hwndPermList;
HWND hwndPrincipalList;
HWND hwndBottom;
HWND hwnd;
LONG i;
TraceEnter(TRACE_PERMPAGE, "CPermPage::OnSize");
if (dwSizeType != SIZE_RESTORED)
TraceLeaveVoid();
hwndPrincipalList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
hwndPermList = GetDlgItem(hDlg, IDC_SPP_PERMS);
hwndAdvButton = GetDlgItem(hDlg, IDC_SPP_ADVANCED);
GetClientRect(hDlg, &rcDlg);
GetWindowRect(hwndPrincipalList, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); // map from screen to dlg
InflateRect(&rcDlg, -rc.left, -rc.top); // account for margins
if (GetWindowLong(hwndAdvButton, GWL_STYLE) & WS_VISIBLE)
{
hwndBottom = hwndAdvButton;
}
else
{
hwndBottom = hwndPermList;
}
GetWindowRect(hwndBottom, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
dy = rcDlg.bottom - rc.bottom;
GetWindowRect(hwndPermList, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
dx = rcDlg.right - rc.right;
//
// Never make things smaller, and only make things
// bigger if the change is worthwhile.
//
dx = max(dx, 0);
if (dx < 5)
dx = 0;
dy = max(dy, 0);
if (dy < 5)
dy = 0;
//
// Reposition and/or resize all controls
//
if (dx > 0 || dy > 0)
{
// Add, Remove, Reset buttons
for (i = IDC_SPP_ADD; i <= IDC_SPP_REMOVE; i++)
{
hwnd = GetDlgItem(hDlg, i);
GetWindowRect(hwnd, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwnd,
NULL,
rc.left + dx,
rc.top + dy/2,
0,
0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}
}
if (dx > 0 || dy > 0)
{
// Listview containing User/Group names
GetWindowRect(hwndPrincipalList, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwndPrincipalList,
NULL,
0,
0,
rc.right - rc.left + dx,
rc.bottom - rc.top + dy/2,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
// Widen the name column if necessary
GetClientRect(hwndPrincipalList, &rc);
if (ListView_GetColumnWidth(hwndPrincipalList, 0) < rc.right)
ListView_SetColumnWidth(hwndPrincipalList, 0, rc.right);
}
if (dy > 0 || dx > 0)
{
// Static control "Access"
hwnd = GetDlgItem(hDlg, IDC_SPP_ACCESS);
GetWindowRect(hwnd, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwnd,
NULL,
rc.left,
rc.top + dy/2,
rc.right - rc.left + dx,
rc.bottom - rc.top,
SWP_NOACTIVATE | SWP_NOZORDER);
//Static control Big Permission Label
hwnd = GetDlgItem(hDlg, IDC_SPP_ACCESS_BIG);
GetWindowRect(hwnd, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwnd,
NULL,
rc.left,
rc.top + dy/2,
rc.right - rc.left + dx,
rc.bottom - rc.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
if (dx > 0 || dy > 0)
{
// Static controls "Allow" and "Deny"
for (i = IDC_SPP_ALLOW; i <= IDC_SPP_DENY; i++)
{
hwnd = GetDlgItem(hDlg, i);
GetWindowRect(hwnd, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwnd,
NULL,
rc.left + dx,
rc.top + dy/2,
0,
0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}
// List of permission checkboxes
GetWindowRect(hwndPermList, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwndPermList,
NULL,
rc.left,
rc.top + dy/2,
rc.right - rc.left + dx,
rc.bottom - rc.top + dy/2,
SWP_NOACTIVATE | SWP_NOZORDER);
}
if (dy > 0 || dx > 0)
{
// Advanced button
GetWindowRect(hwndAdvButton, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwndAdvButton,
NULL,
rc.left + dx,
rc.top + dy,
0,
0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
// "More stuff is present but not viewable" message
hwnd = GetDlgItem(hDlg, IDC_SPP_STATIC_ADV);
GetWindowRect(hwnd, &rc);
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
SetWindowPos(hwnd,
NULL,
rc.left,
rc.top + dy,
0,
0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}
TraceLeaveVoid();
}
void
CPermPage::ClearPermissions(HWND hwndList, BOOL bDisabled)
{
// Uncheck everything
UINT cRights = 0;
DWORD dwState = CLST_UNCHECKED;
if (bDisabled)
dwState |= CLST_DISABLED;
if (hwndList)
cRights = (UINT)SendMessage(hwndList, CLM_GETITEMCOUNT, 0, 0);
while (cRights > 0)
{
cRights--;
SendMessage(hwndList, CLM_SETSTATE, MAKELONG((WORD)cRights, 1), dwState);
SendMessage(hwndList, CLM_SETSTATE, MAKELONG((WORD)cRights, 2), dwState);
}
if(m_bCustomPermission)
{
ClearCustom(hwndList,1);
ClearCustom(hwndList,2);
}
}
void
CPermPage::SetDirty(HWND hDlg, BOOL bDefault)
{
if (!bDefault)
m_wSDControl &= ~SE_DACL_DEFAULTED;
m_fPageDirty = TRUE;
PropSheet_Changed(GetParent(hDlg), hDlg);
}
BOOL
CPermPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// First check to see if its time to update listview names
if (uMsg == UM_SIDLOOKUPCOMPLETE)
{
HWND hwndList = GetDlgItem(hDlg, IDC_SPP_PRINCIPALS);
SetPrincipalNamesInList(hwndList, (PSID)lParam);
SetPermLabelText(hDlg);
// lParam is zero when all remaining names are looked up
if (0 == lParam)
{
// Sort using the real names
ListView_SortItems(hwndList, NULL, 0);
// Make sure the selected item is visible
int iSelItem;
if (NULL == GetSelectedItemData(hwndList, &iSelItem))
{
// No selection, select the first item
SelectListViewItem(hwndList, 0);
}
else
{
ListView_EnsureVisible(hwndList, iSelItem, FALSE);
}
// Show normal cursor now
m_fBusy = FALSE;
SetCursor(LoadCursor(NULL, IDC_ARROW));
// Enable the Advanced button if appropriate
EnableWindow(GetDlgItem(hDlg, IDC_SPP_ADVANCED),
(m_siObjectInfo.dwFlags & SI_ADVANCED));
}
return TRUE;
}
switch(uMsg)
{
case WM_SETCURSOR:
if (m_fBusy)
{
SetCursor(m_hcurBusy);
SetWindowLong(hDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
else
return FALSE;
break;
case WM_INITDIALOG:
return InitDlg(hDlg);
case WM_NOTIFY:
return OnNotify(hDlg, (int)wParam, (LPNMHDR)lParam);
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_SPP_ADD:
OnAddPrincipal(hDlg);
break;
case IDC_SPP_REMOVE:
OnRemovePrincipal(hDlg);
break;
case IDC_SPP_ADVANCED:
OnAdvanced(hDlg);
break;
case IDC_SPP_PRINCIPALS:
if (GET_WM_COMMAND_CMD(wParam, lParam) == IDN_CHECKSELECTION)
{
// See if we have gotten a new selection. If not, then the
// user must have clicked inside the listview but not on an item,
// thus causing the listview to remove the selection. In that
// case, disable the other controls
if (ListView_GetSelectedCount(GET_WM_COMMAND_HWND(wParam, lParam)) == 0)
{
// Uncheck everything first
ClearPermissions(GetDlgItem(hDlg, IDC_SPP_PERMS));
EnablePrincipalControls(hDlg, FALSE);
}
}
break;
default:
// Command not handled
return FALSE;
}
break;
case WM_SIZE:
OnSize(hDlg, (LONG)wParam, (ULONG)LOWORD(lParam), (ULONG)HIWORD(lParam));
break;
case WM_HELP:
if (IsWindowEnabled(hDlg))
{
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
c_szAcluiHelpFile,
HELP_WM_HELP,
(DWORD_PTR)aPermPageHelpIDs);
}
break;
case WM_CONTEXTMENU:
if (IsWindowEnabled(hDlg))
{
HWND hwnd = (HWND)wParam;
//
// 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_SPP_PERMS)
hwnd = GetDlgItem(hDlg, IDC_SPP_ACCESS);
WinHelp(hwnd,
c_szAcluiHelpFile,
HELP_CONTEXTMENU,
(DWORD_PTR)aPermPageHelpIDs);
}
break;
default:
// Message not handled
return FALSE;
}
return TRUE;
}
//
// CSecurityInfo implementation
//
STDMETHODIMP_(ULONG)
CSecurityInfo::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CSecurityInfo::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CSecurityInfo::QueryInterface(REFIID riid, LPVOID FAR* ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
*ppv = static_cast<LPSECURITYINFO>(this);
else if (IsEqualIID(riid, IID_ISecurityInformation2))
{
if (m_pPage->m_psi2)
*ppv = static_cast<LPSECURITYINFO2>(this);
}
else if (IsEqualIID(riid, IID_IEffectivePermission))
{
if(m_pPage->m_pei)
*ppv = static_cast<LPEFFECTIVEPERMISSION>(this);
}
else if (IsEqualIID(riid, IID_ISecurityObjectTypeInfo))
{
if(m_pPage->m_psoti)
*ppv = static_cast<LPSecurityObjectTypeInfo>(this);
}
#if(_WIN32_WINNT >= 0x0500)
else if (IsEqualIID(riid, IID_IDsObjectPicker))
*ppv = static_cast<IDsObjectPicker*>(this);
#endif
if (*ppv)
{
m_cRef++;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP
CSecurityInfo::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
{
TraceEnter(TRACE_SI, "CSecurityInfo::GetObjectInformation");
TraceAssert(m_pPage != NULL);
*pObjectInfo = m_pPage->m_siObjectInfo;
TraceLeaveResult(S_OK);
}
STDMETHODIMP
CSecurityInfo::GetSecurity(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR *ppSD,
BOOL fDefault)
{
HRESULT hr;
TraceEnter(TRACE_SI, "CSecurityInfo::GetSecurity");
TraceAssert(si != 0);
TraceAssert(ppSD != NULL);
TraceAssert(m_pPage != NULL);
TraceAssert(m_hDlg != NULL);
*ppSD = NULL;
//Effective permission page calls with si = DACL + OWNER + GROUP and it should
//return Actual Security Descriptor. Other pages calls with only one thing at a time
//and we build dacl and return it if its dirty.
if (!fDefault && (si == DACL_SECURITY_INFORMATION) && m_pPage->m_fPageDirty)
{
// We only get asked for one thing at a time
TraceAssert(si == DACL_SECURITY_INFORMATION);
// Return current DACL, including inherited ACEs
hr = m_pPage->BuildDacl(m_hDlg, ppSD, TRUE);
}
else
{
TraceAssert(m_pPage->m_psi != NULL);
// Get it from the object
hr = m_pPage->m_psi->GetSecurity(si, ppSD, fDefault);
}
TraceLeaveResult(hr);
}
STDMETHODIMP
CSecurityInfo::SetSecurity(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD)
{
HRESULT hr = E_FAIL;
TraceEnter(TRACE_SI, "CSecurityInfo::SetSecurity");
TraceAssert(si != 0);
TraceAssert(pSD != NULL);
TraceAssert(m_pPage != NULL);
TraceAssert(m_hDlg != NULL);
// Write out the new security descriptor
if (m_pPage->m_psi != NULL)
hr = m_pPage->m_psi->SetSecurity(si, pSD);
if (S_OK == hr && (si & DACL_SECURITY_INFORMATION))
{
PSECURITY_DESCRIPTOR psd = NULL;
m_pPage->m_fPageDirty = FALSE;
// Read the new DACL back from the object, that is, don't use the one
// from the passed-in security descriptor. This ensures that we have
// the "real" current DACL in case it was modified somewhere en route.
if (SUCCEEDED(m_pPage->m_psi->GetSecurity(DACL_SECURITY_INFORMATION, &psd, FALSE)))
pSD = psd;
// Reinitialize the dialog using the new DACL
m_pPage->SetDacl(m_hDlg, pSD);
if (psd != NULL)
LocalFree(psd);
}
TraceLeaveResult(hr);
}
STDMETHODIMP
CSecurityInfo::GetAccessRights(const GUID* pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess)
{
HRESULT hr = E_FAIL;
TraceEnter(TRACE_SI, "CSecurityInfo::GetAccessRights");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_psi != NULL)
hr = m_pPage->m_psi->GetAccessRights(pguidObjectType,
dwFlags,
ppAccess,
pcAccesses,
piDefaultAccess);
TraceLeaveResult(hr);
}
STDMETHODIMP
CSecurityInfo::MapGeneric(const GUID* pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pmask)
{
HRESULT hr = E_FAIL;
TraceEnter(TRACE_SI, "CSecurityInfo::MapGeneric");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_psi != NULL)
hr = m_pPage->m_psi->MapGeneric(pguidObjectType, pAceFlags, pmask);
TraceLeaveResult(hr);
}
STDMETHODIMP
CSecurityInfo::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes)
{
HRESULT hr = E_FAIL;
TraceEnter(TRACE_SI, "CSecurityInfo::GetInheritTypes");
TraceAssert(m_pPage != NULL);
TraceAssert(ppInheritTypes != NULL);
TraceAssert(pcInheritTypes != NULL);
*ppInheritTypes = NULL;
*pcInheritTypes = 0;
if (m_pPage->m_psi != NULL)
hr = m_pPage->m_psi->GetInheritTypes(ppInheritTypes,
pcInheritTypes);
TraceLeaveResult(hr);
}
STDMETHODIMP
CSecurityInfo::PropertySheetPageCallback(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage)
{
HRESULT hr = S_OK;
TraceEnter(TRACE_SI, "CSecurityInfo::PropertySheetPageCallback");
TraceAssert(m_pPage != NULL);
//
// Pass the call on to the client
//
if (m_pPage->m_psi != NULL)
hr = m_pPage->m_psi->PropertySheetPageCallback(hwnd, uMsg, uPage);
//
// If the simple perm page is disabled, make sure the advanced perm
// page is as well.
//
if (SUCCEEDED(hr) && uPage == SI_PAGE_ADVPERM && m_pPage->m_bAbortPage)
hr = E_FAIL;
TraceLeaveResult(hr);
}
//
// ISecurityInformation2 methods
//
STDMETHODIMP_(BOOL)
CSecurityInfo::IsDaclCanonical(PACL pDacl)
{
BOOL bResult = TRUE;
TraceEnter(TRACE_SI, "CSecurityInfo::IsDaclCanonical");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_psi2 != NULL)
bResult = m_pPage->m_psi2->IsDaclCanonical(pDacl);
TraceLeaveValue(bResult);
}
STDMETHODIMP
CSecurityInfo::LookupSids(ULONG cSids, PSID *rgpSids, LPDATAOBJECT *ppdo)
{
HRESULT hr = E_NOTIMPL;
TraceEnter(TRACE_SI, "CSecurityInfo::LookupSids");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_psi2 != NULL)
hr = m_pPage->m_psi2->LookupSids(cSids, rgpSids, ppdo);
TraceLeaveResult(hr);
}
//
// IDsObjectPicker methods
//
#if(_WIN32_WINNT >= 0x0500)
STDMETHODIMP CSecurityInfo::Initialize(PDSOP_INIT_INFO pInitInfo)
{
HRESULT hr;
IDsObjectPicker *pObjectPicker = NULL;
hr = m_pPage->GetObjectPicker(&pObjectPicker);
if (SUCCEEDED(hr))
{
if (m_pPage->m_flLastOPOptions != pInitInfo->flOptions)
{
m_pPage->m_flLastOPOptions = (DWORD)-1;
hr = pObjectPicker->Initialize(pInitInfo);
if (SUCCEEDED(hr))
{
m_pPage->m_flLastOPOptions = pInitInfo->flOptions;
}
}
pObjectPicker->Release();
}
return hr;
}
STDMETHODIMP CSecurityInfo::InvokeDialog(HWND hwndParent,
IDataObject **ppdoSelection)
{
HRESULT hr;
IDsObjectPicker *pObjectPicker = NULL;
hr = m_pPage->GetObjectPicker(&pObjectPicker);
if (SUCCEEDED(hr))
{
hr = pObjectPicker->InvokeDialog(hwndParent, ppdoSelection);
pObjectPicker->Release();
}
return hr;
}
#endif // _WIN32_WINNT >= 0x0500
STDMETHODIMP CSecurityInfo::GetInheritSource(SECURITY_INFORMATION si,
PACL pACL,
PINHERITED_FROM *ppInheritArray)
{
HRESULT hr = E_NOTIMPL;
TraceEnter(TRACE_SI, "CSecurityInfo::GetInheritSource");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_psoti)
hr = m_pPage->m_psoti->GetInheritSource(si, pACL, ppInheritArray);
TraceLeaveResult(hr);
}
STDMETHODIMP CSecurityInfo::GetEffectivePermission( THIS_ const GUID* pguidObjectType,
PSID pUserSid,
LPCWSTR pszServerName,
PSECURITY_DESCRIPTOR pSD,
POBJECT_TYPE_LIST *ppObjectTypeList,
ULONG *pcObjectTypeListLength,
PACCESS_MASK *ppGrantedAccessList,
ULONG *pcGrantedAccessListLength)
{
HRESULT hr = E_NOTIMPL;
TraceEnter(TRACE_SI, "CSecurityInfo::GetEffectivePermission");
TraceAssert(m_pPage != NULL);
if (m_pPage->m_pei)
hr = m_pPage->m_pei->GetEffectivePermission(pguidObjectType,
pUserSid,
pszServerName,
pSD,
ppObjectTypeList,
pcObjectTypeListLength,
ppGrantedAccessList,
pcGrantedAccessListLength);
TraceLeaveResult(hr);
}
//
// Expose an api to get at the simple permission editor
//
HPROPSHEETPAGE
ACLUIAPI
CreateSecurityPage(LPSECURITYINFO psi)
{
HPROPSHEETPAGE hPage = NULL;
PPERMPAGE pPage;
PSIDCACHE pSidCache;
TraceEnter(TRACE_PERMPAGE, "CreateSecurityPage");
// Create the global SID Cache
pSidCache = GetSidCache();
if (NULL == psi)
{
SetLastError(ERROR_INVALID_PARAMETER);
TraceLeaveValue(NULL);
}
pPage = new CPermPage(psi);
if (pPage)
{
SI_OBJECT_INFO siObjectInfo = {0};
LPCTSTR pszTitle = NULL;
if (SUCCEEDED(psi->GetObjectInformation(&siObjectInfo)) &&
(siObjectInfo.dwFlags & SI_PAGE_TITLE))
{
pszTitle = siObjectInfo.pszPageTitle;
}
hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(IDD_SIMPLE_PERM_PAGE), pszTitle);
if (!hPage)
delete pPage;
}
if (pSidCache)
pSidCache->Release();
TraceLeaveValue(hPage);
}
BOOL
ACLUIAPI
EditSecurity( HWND hwndOwner, LPSECURITYINFO psi )
{
HPROPSHEETPAGE hPage[1];
UINT cPages = 0;
BOOL bResult = FALSE;
SI_OBJECT_INFO siObjectInfo = {0};
HRESULT hr;
TraceEnter(TRACE_PERMPAGE, "EditSecurity");
// Get object name for dialog title
hr = psi->GetObjectInformation(&siObjectInfo);
if (FAILED(hr))
{
if (!GetLastError())
SetLastError(hr);
TraceLeaveValue(FALSE);
}
hPage[cPages] = CreateSecurityPage( psi );
if (hPage[cPages])
cPages++;
if (cPages)
{
// Build dialog title string
LPTSTR pszCaption = NULL;
PROPSHEETHEADER psh;
psh.dwSize = SIZEOF(psh);
psh.dwFlags = PSH_DEFAULT;
psh.hwndParent = hwndOwner;
psh.hInstance = ::hModule;
psh.nPages = cPages;
psh.nStartPage = 0;
psh.phpage = &hPage[0];
// There has been a request for customization of this dialog title,
// but this probably isn't the best way to do it, since the dlg title
// and page title will be the same.
#if 0
if ((siObjectInfo.dwFlags & SI_PAGE_TITLE)
&& siObjectInfo.pszPageTitle
&& siObjectInfo.pszPageTitle[0])
{
psh.pszCaption = siObjectInfo.pszPageTitle;
}
else
#endif
{
FormatStringID(&pszCaption, ::hModule, IDS_SPP_TITLE, siObjectInfo.pszObjectName);
psh.pszCaption = pszCaption;
}
bResult = (BOOL)(PropertySheet(&psh) + 1);
LocalFreeString(&pszCaption);
}
TraceLeaveValue(bResult);
}
//