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.
3328 lines
104 KiB
3328 lines
104 KiB
#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);
|
|
}
|
|
|
|
//Remveod the special casing for CREATOR_OWNER
|
|
//NTRAID#NTBUG9-467049-2001/11/29-hiteshr
|
|
|
|
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)
|
|
{
|
|
pAccess = &m_CustomAccess;
|
|
ZeroMemory(pAccess, sizeof(SI_ACCESS));
|
|
|
|
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 rcLabel;
|
|
WCHAR szBuffer[MAX_COLUMN_CHARS];
|
|
HWND hwndLabel;
|
|
HWND hwndList;
|
|
LPTSTR pszCaption = NULL;
|
|
SIZE size;
|
|
LPCWSTR pszUserName = NULL;
|
|
CPrincipal * pPrincipal = NULL;
|
|
int iIndex = 0;
|
|
|
|
//Get the text to display
|
|
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);
|
|
|
|
//Get Label Dimension
|
|
hwndLabel = GetDlgItem(hDlg, IDC_SPP_ACCESS);
|
|
GetClientRect(hwndLabel, &rcLabel);
|
|
|
|
//Get the device context and set its font to font of label
|
|
HDC hdc = GetDC(hwndLabel);
|
|
SelectObject(hdc,(HGDIOBJ)SendMessage(hwndLabel,WM_GETFONT,0,0));
|
|
|
|
BOOL bUseBig = false;
|
|
RECT rcText = {0};
|
|
if( DrawText(hdc, pszCaption, wcslen(pszCaption), &rcText, DT_CALCRECT)
|
|
&& rcText.right > rcLabel.right )
|
|
{
|
|
bUseBig = true;
|
|
}
|
|
|
|
if(bUseBig)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
BOOL bCallBackAces = FALSE;
|
|
|
|
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(hr == S_FALSE)
|
|
{
|
|
//ISecuirtyInformation impelmentation has already shown
|
|
//error message. This is fatal failure and we should
|
|
//disable all the controls
|
|
hr = E_FAIL;
|
|
FailGracefully(hr, "GetSecurity returned S_FALSE");
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
|
|
//Check if there are any call back aces. We don't support
|
|
//callback aces
|
|
if(bCallBackAces = IsCallBackAcePresentInSD(pSD))
|
|
{
|
|
hr = E_FAIL;
|
|
FailGracefully(hr, "Callback Aces present");
|
|
}
|
|
// 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;
|
|
m_bNoReadWriteCanWriteOwner = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SI_EDIT_AUDITS:
|
|
{
|
|
// Can edit the SACL and write the Owner
|
|
m_bNoReadWriteCanWriteOwner = TRUE;
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if(bCallBackAces)
|
|
{
|
|
WCHAR szBuf[1024];
|
|
LoadString(::hModule,IDS_CALLBACK_ACE_PRESENT,szBuf,ARRAYSIZE(szBuf));
|
|
SetDlgItemText(hDlg,IDC_SPP_NO_SECURITY,szBuf);
|
|
}
|
|
// 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);
|
|
|
|
if(!InitializeSecurityDescriptor(*ppSD, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
LocalFree(*ppSD);
|
|
*ppSD = NULL;
|
|
DWORD dwErr = GetLastError();
|
|
TraceLeaveResult(HRESULT_FROM_WIN32(dwErr));
|
|
}
|
|
|
|
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;
|
|
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);
|
|
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));
|
|
|
|
//Remveod the special casing for CREATOR_OWNER
|
|
//NTRAID#NTBUG9-467049-2001/11/29-hiteshr
|
|
}
|
|
|
|
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,m_bNoReadWriteCanWriteOwner);
|
|
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);
|
|
|
|
}
|
|
|
|
else if (IsEqualIID(riid, IID_IDsObjectPicker))
|
|
*ppv = static_cast<IDsObjectPicker*>(this);
|
|
|
|
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
|
|
//
|
|
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;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
//
|