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

542 lines
17 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: pagebase.cpp
//
// This file contains the implementation of the CSecurityPage base class.
//
//--------------------------------------------------------------------------
#include "aclpriv.h"
CSecurityPage::CSecurityPage( LPSECURITYINFO psi, SI_PAGE_TYPE siType )
: m_siPageType(siType), m_psi(psi), m_psi2(NULL),m_pei(NULL), m_pObjectPicker(NULL),
m_psoti(NULL),
m_flLastOPOptions(DWORD(-1))
{
ZeroMemory(&m_siObjectInfo, sizeof(m_siObjectInfo));
// Initialize COM incase our client hasn't
m_hrComInit = CoInitialize(NULL);
if (m_psi != NULL)
{
m_psi->AddRef();
// It's normal for this to fail
m_psi->QueryInterface(IID_ISecurityInformation2, (LPVOID*)&m_psi2);
m_psi->QueryInterface(IID_IEffectivePermission, (LPVOID*)&m_pei);
m_psi->QueryInterface(IID_ISecurityObjectTypeInfo, (LPVOID*)&m_psoti);
}
}
CSecurityPage::~CSecurityPage( void )
{
DoRelease(m_psi);
DoRelease(m_psi2);
DoRelease(m_pObjectPicker);
DoRelease(m_pei);
DoRelease(m_psoti);
if (SUCCEEDED(m_hrComInit))
CoUninitialize();
}
HPROPSHEETPAGE
CSecurityPage::CreatePropSheetPage(LPCTSTR pszDlgTemplate, LPCTSTR pszDlgTitle)
{
PROPSHEETPAGE psp;
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_USECALLBACK ;
psp.hInstance = ::hModule;
psp.pszTemplate = pszDlgTemplate;
psp.pszTitle = pszDlgTitle;
psp.pfnDlgProc = CSecurityPage::_DlgProc;
psp.lParam = (LPARAM)this;
psp.pfnCallback = CSecurityPage::_PSPageCallback;
if (pszDlgTitle != NULL)
psp.dwFlags |= PSP_USETITLE;
return CreatePropertySheetPage(&psp);
}
HRESULT
CSecurityPage::GetObjectPicker(IDsObjectPicker **ppObjectPicker)
{
#if(_WIN32_WINNT >= 0x0500)
HRESULT hr = S_OK;
if (!m_pObjectPicker)
{
if (!m_psi)
return E_UNEXPECTED;
// See if the object supports IDsObjectPicker
hr = m_psi->QueryInterface(IID_IDsObjectPicker, (LPVOID*)&m_pObjectPicker);
// If the object doesn't support IDsObjectPicker, create one.
if (FAILED(hr))
{
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(LPVOID*)&m_pObjectPicker);
}
}
if (ppObjectPicker)
{
*ppObjectPicker = m_pObjectPicker;
// Return a reference (caller must Release)
if (m_pObjectPicker)
m_pObjectPicker->AddRef();
}
return hr;
#else
*ppObjectPicker = NULL;
return E_NOTIMPL;
#endif
}
#if(_WIN32_WINNT >= 0x0500)
//
// Stuff used for initializing the Object Picker below
//
#define DSOP_FILTER_COMMON1 ( DSOP_FILTER_INCLUDE_ADVANCED_VIEW \
| DSOP_FILTER_USERS \
| DSOP_FILTER_UNIVERSAL_GROUPS_SE \
| DSOP_FILTER_GLOBAL_GROUPS_SE \
| DSOP_FILTER_COMPUTERS \
)
#define DSOP_FILTER_COMMON2 ( DSOP_FILTER_COMMON1 \
| DSOP_FILTER_WELL_KNOWN_PRINCIPALS \
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE\
)
#define DSOP_FILTER_COMMON3 ( DSOP_FILTER_COMMON2 \
| DSOP_FILTER_BUILTIN_GROUPS \
)
#define DSOP_FILTER_DL_COMMON1 ( DSOP_DOWNLEVEL_FILTER_USERS \
| DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS \
)
#define DSOP_FILTER_DL_COMMON2 ( DSOP_FILTER_DL_COMMON1 \
| DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS \
)
#define DSOP_FILTER_DL_COMMON3 ( DSOP_FILTER_DL_COMMON2 \
| DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS \
)
// Same as DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS, except no CREATOR flags.
// Note that we need to keep this in sync with any object picker changes.
#define DSOP_FILTER_DL_WELLKNOWN ( DSOP_DOWNLEVEL_FILTER_WORLD \
| DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER \
| DSOP_DOWNLEVEL_FILTER_ANONYMOUS \
| DSOP_DOWNLEVEL_FILTER_BATCH \
| DSOP_DOWNLEVEL_FILTER_DIALUP \
| DSOP_DOWNLEVEL_FILTER_INTERACTIVE \
| DSOP_DOWNLEVEL_FILTER_NETWORK \
| DSOP_DOWNLEVEL_FILTER_SERVICE \
| DSOP_DOWNLEVEL_FILTER_SYSTEM \
| DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER \
)
#if 0
{ // DSOP_SCOPE_INIT_INFO
cbSize,
flType,
flScope,
{ // DSOP_FILTER_FLAGS
{ // DSOP_UPLEVEL_FILTER_FLAGS
flBothModes,
flMixedModeOnly,
flNativeModeOnly
},
flDownlevel
},
pwzDcName,
pwzADsPath,
hr // OUT
}
#endif
#define DECLARE_SCOPE(t,f,b,m,n,d) \
{ sizeof(DSOP_SCOPE_INIT_INFO), (t), (f|DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS), { { (b), (m), (n) }, (d) }, NULL, NULL, S_OK }
// The domain to which the target computer is joined.
// Make 2 scopes, one for uplevel domains, the other for downlevel.
#define JOINED_DOMAIN_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON2 & ~(DSOP_FILTER_UNIVERSAL_GROUPS_SE|DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE)),DSOP_FILTER_COMMON2,0), \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON2)
// The domain for which the target computer is a Domain Controller.
// Make 2 scopes, one for uplevel domains, the other for downlevel.
#define JOINED_DOMAIN_SCOPE_DC(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON3 & ~DSOP_FILTER_UNIVERSAL_GROUPS_SE),DSOP_FILTER_COMMON3,0), \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
// Target computer scope. Computer scopes are always treated as
// downlevel (i.e., they use the WinNT provider).
#define TARGET_COMPUTER_SCOPE(f)\
DECLARE_SCOPE(DSOP_SCOPE_TYPE_TARGET_COMPUTER,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
// The Global Catalog
#define GLOBAL_CATALOG_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_GLOBAL_CATALOG,(f),DSOP_FILTER_COMMON1|DSOP_FILTER_WELL_KNOWN_PRINCIPALS,0,0,0)
// The domains in the same forest (enterprise) as the domain to which
// the target machine is joined. Note these can only be DS-aware
#define ENTERPRISE_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN,(f),DSOP_FILTER_COMMON1,0,0,0)
// Domains external to the enterprise but trusted directly by the
// domain to which the target machine is joined.
#define EXTERNAL_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN|DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN,\
(f),DSOP_FILTER_COMMON1,0,0,DSOP_DOWNLEVEL_FILTER_USERS|DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS)
// Workgroup scope. Only valid if the target computer is not joined
// to a domain.
#define WORKGROUP_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_WORKGROUP,(f),0,0,0, DSOP_FILTER_DL_COMMON1|DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS )
//
// Array of Default Scopes
//
static const DSOP_SCOPE_INIT_INFO g_aDefaultScopes[] =
{
JOINED_DOMAIN_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE),
TARGET_COMPUTER_SCOPE(0),
GLOBAL_CATALOG_SCOPE(0),
ENTERPRISE_SCOPE(0),
EXTERNAL_SCOPE(0),
};
//
// Same as above, but without the Target Computer
// Used when the target is a Domain Controller
//
static const DSOP_SCOPE_INIT_INFO g_aDCScopes[] =
{
JOINED_DOMAIN_SCOPE_DC(DSOP_SCOPE_FLAG_STARTING_SCOPE),
GLOBAL_CATALOG_SCOPE(0),
ENTERPRISE_SCOPE(0),
EXTERNAL_SCOPE(0),
};
//
// Array of scopes for standalone machines
//
static const DSOP_SCOPE_INIT_INFO g_aStandAloneScopes[] =
{
//
//On Standalone machine Both User And Groups are selected by default
//
TARGET_COMPUTER_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS),
};
//
// Attributes that we want the Object Picker to retrieve
//
static const LPCTSTR g_aszOPAttributes[] =
{
TEXT("ObjectSid"),
};
HRESULT
CSecurityPage::InitObjectPicker(BOOL bMultiSelect)
{
HRESULT hr = S_OK;
DSOP_INIT_INFO InitInfo;
PCDSOP_SCOPE_INIT_INFO pScopes;
ULONG cScopes;
USES_CONVERSION;
TraceEnter(TRACE_MISC, "InitObjectPicker");
hr = GetObjectPicker();
if (FAILED(hr))
TraceLeaveResult(hr);
TraceAssert(m_pObjectPicker != NULL);
InitInfo.cbSize = sizeof(InitInfo);
// We do the DC check at WM_INITDIALOG
InitInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;
if (bMultiSelect)
InitInfo.flOptions |= DSOP_FLAG_MULTISELECT;
// flOptions is the only thing that changes from call to call,
// so optimize this by only reinitializing if flOptions changes.
if (m_flLastOPOptions == InitInfo.flOptions)
TraceLeaveResult(S_OK); // Already initialized
m_flLastOPOptions = (DWORD)-1;
pScopes = g_aDefaultScopes;
cScopes = ARRAYSIZE(g_aDefaultScopes);
if (m_bStandalone)
{
cScopes = ARRAYSIZE(g_aStandAloneScopes);
pScopes = g_aStandAloneScopes;
}
else if (m_siObjectInfo.dwFlags & SI_SERVER_IS_DC)
{
cScopes = ARRAYSIZE(g_aDCScopes);
pScopes = g_aDCScopes;
}
//
// The pwzTargetComputer member allows the object picker to be
// retargetted to a different computer. It will behave as if it
// were being run ON THAT COMPUTER.
//
InitInfo.pwzTargetComputer = T2CW(m_siObjectInfo.pszServerName);
InitInfo.cDsScopeInfos = cScopes;
InitInfo.aDsScopeInfos = (PDSOP_SCOPE_INIT_INFO)LocalAlloc(LPTR, sizeof(*pScopes)*cScopes);
if (!InitInfo.aDsScopeInfos)
TraceLeaveResult(E_OUTOFMEMORY);
CopyMemory(InitInfo.aDsScopeInfos, pScopes, sizeof(*pScopes)*cScopes);
InitInfo.cAttributesToFetch = ARRAYSIZE(g_aszOPAttributes);
InitInfo.apwzAttributeNames = (LPCTSTR*)g_aszOPAttributes;
if ((m_siObjectInfo.dwFlags & SI_SERVER_IS_DC) || !(m_siObjectInfo.dwFlags & SI_CONTAINER))
{
for (ULONG i = 0; i < cScopes; i++)
{
// Set the DC name if appropriate
if ((m_siObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
(InitInfo.aDsScopeInfos[i].flType & DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN))
{
InitInfo.aDsScopeInfos[i].pwzDcName = InitInfo.pwzTargetComputer;
}
// Turn off CREATOR_OWNER & CREATOR_GROUP for non-containers
if (!(m_siObjectInfo.dwFlags & SI_CONTAINER) &&
(InitInfo.aDsScopeInfos[i].FilterFlags.flDownlevel & DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS))
{
InitInfo.aDsScopeInfos[i].FilterFlags.flDownlevel &= ~DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS;
InitInfo.aDsScopeInfos[i].FilterFlags.flDownlevel |= DSOP_FILTER_DL_WELLKNOWN;
}
}
}
hr = m_pObjectPicker->Initialize(&InitInfo);
if (SUCCEEDED(hr))
{
// Remember the Options for next time
m_flLastOPOptions = InitInfo.flOptions;
}
LocalFree(InitInfo.aDsScopeInfos);
TraceLeaveResult(hr);
}
#endif // (_WIN32_WINNT >= 0x0500)
HRESULT
CSecurityPage::GetUserGroup(HWND hDlg, BOOL bMultiSelect, PUSER_LIST *ppUserList)
{
#if(_WIN32_WINNT < 0x0500)
DWORD dwFlags = 0;
if (bMultiSelect)
dwFlags |= GU_MULTI_SELECT;
if (m_siObjectInfo.dwFlags & SI_CONTAINER)
dwFlags |= GU_CONTAINER;
if (m_siObjectInfo.dwFlags & SI_SERVER_IS_DC)
dwFlags |= GU_DC_SERVER;
if (m_siPageType == SI_PAGE_AUDIT)
dwFlags |= GU_AUDIT_HLP;
return ::GetUserGroup(hDlg,
dwFlags,
m_siObjectInfo.pszServerName,
m_bStandalone,
ppUserList);
#else // (_WIN32_WINNT >= 0x0500)
HRESULT hr;
LPDATAOBJECT pdoSelection = NULL;
STGMEDIUM medium = {0};
FORMATETC fe = { (CLIPFORMAT)g_cfDsSelectionList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
PDS_SELECTION_LIST pDsSelList = NULL;
HCURSOR hcur = NULL;
PSIDCACHE pSidCache = NULL;
UINT idErrorMsg = IDS_GET_USER_FAILED;
TraceEnter(TRACE_MISC, "GetUserGroup");
TraceAssert(ppUserList != NULL);
*ppUserList = NULL;
//
// Create and initialize the Object Picker object
//
hr = InitObjectPicker(bMultiSelect);
FailGracefully(hr, "Unable to initialize Object Picker object");
//
// Create the global sid cache object, if necessary
//
pSidCache = GetSidCache();
if (pSidCache == NULL)
ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create SID cache");
//
// Bring up the object picker dialog
//
hr = m_pObjectPicker->InvokeDialog(hDlg, &pdoSelection);
FailGracefully(hr, "IDsObjectPicker->Invoke failed");
if (S_FALSE == hr)
ExitGracefully(hr, S_FALSE, "IDsObjectPicker->Invoke cancelled by user");
hr = pdoSelection->GetData(&fe, &medium);
FailGracefully(hr, "Unable to get CFSTR_DSOP_DS_SELECTION_LIST from DataObject");
pDsSelList = (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);
if (!pDsSelList)
ExitGracefully(hr, E_FAIL, "Unable to lock stgmedium.hGlobal");
TraceAssert(pDsSelList->cItems > 0);
Trace((TEXT("%d items selected"), pDsSelList->cItems));
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Lookup the names/sids and cache them
//
if (!pSidCache->LookupNames(pDsSelList,
m_siObjectInfo.pszServerName,
ppUserList,
m_bStandalone))
{
hr = E_FAIL;
idErrorMsg = IDS_SID_LOOKUP_FAILED;
}
SetCursor(hcur);
exit_gracefully:
if (pSidCache)
pSidCache->Release();
if (FAILED(hr))
{
SysMsgPopup(hDlg,
MAKEINTRESOURCE(idErrorMsg),
MAKEINTRESOURCE(IDS_SECURITY),
MB_OK | MB_ICONERROR,
::hModule,
hr);
}
if (pDsSelList)
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
DoRelease(pdoSelection);
TraceLeaveResult(hr);
#endif // (_WIN32_WINNT >= 0x0500)
}
UINT
CSecurityPage::PSPageCallback(HWND hwnd,
UINT uMsg,
LPPROPSHEETPAGE /*ppsp*/)
{
m_hrLastPSPCallbackResult = E_FAIL;
if (m_psi != NULL)
{
m_hrLastPSPCallbackResult = m_psi->PropertySheetPageCallback(hwnd, uMsg, m_siPageType);
if (m_hrLastPSPCallbackResult == E_NOTIMPL)
m_hrLastPSPCallbackResult = S_OK;
}
return SUCCEEDED(m_hrLastPSPCallbackResult);
}
INT_PTR
CALLBACK
CSecurityPage::_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPSECURITYPAGE pThis = (LPSECURITYPAGE)GetWindowLongPtr(hDlg, DWLP_USER);
// The following messages arrive before WM_INITDIALOG
// which means pThis is NULL for them. We don't need these
// messages so let DefDlgProc handle them.
//
// WM_SETFONT
// WM_NOTIFYFORMAT
// WM_NOTIFY (LVN_HEADERCREATED)
if (uMsg == WM_INITDIALOG)
{
pThis = (LPSECURITYPAGE)(((LPPROPSHEETPAGE)lParam)->lParam);
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pThis);
if (pThis)
{
if (!pThis->PSPageCallback(hDlg, PSPCB_SI_INITDIALOG, NULL))
pThis->m_bAbortPage = TRUE;
if (pThis->m_psi)
{
BOOL bIsDC = FALSE;
pThis->m_psi->GetObjectInformation(&pThis->m_siObjectInfo);
pThis->m_bStandalone = IsStandalone(pThis->m_siObjectInfo.pszServerName, &bIsDC);
if (bIsDC)
pThis->m_siObjectInfo.dwFlags |= SI_SERVER_IS_DC;
}
}
}
if (pThis != NULL)
return pThis->DlgProc(hDlg, uMsg, wParam, lParam);
return FALSE;
}
UINT
CALLBACK
CSecurityPage::_PSPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
{
LPSECURITYPAGE pThis = (LPSECURITYPAGE)ppsp->lParam;
if (pThis)
{
UINT nResult = pThis->PSPageCallback(hWnd, uMsg, ppsp);
switch (uMsg)
{
case PSPCB_CREATE:
if (!nResult)
pThis->m_bAbortPage = TRUE;
break;
case PSPCB_RELEASE:
delete pThis;
break;
}
}
//
// Always return non-zero or else our tab will disappear and whichever
// property page becomes active won't repaint properly. Instead, use
// the m_bAbortPage flag during WM_INITDIALOG to disable the page if
// the callback failed.
//
return 1;
}