|
|
//+-------------------------------------------------------------------------
//
// 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) { 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; }
//
// 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 \ )
#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"), TEXT("userAccountControl"), };
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) { 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; }
} }
hr = m_pObjectPicker->Initialize(&InitInfo);
if (SUCCEEDED(hr)) { // Remember the Options for next time
m_flLastOPOptions = InitInfo.flOptions; }
LocalFree(InitInfo.aDsScopeInfos);
TraceLeaveResult(hr); }
HRESULT CSecurityPage::GetUserGroup(HWND hDlg, BOOL bMultiSelect, PUSER_LIST *ppUserList) { 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));
//Check if there is any disabled items
if(!DoDisabledCheck(hDlg, pDsSelList)) { return S_FALSE; }
//
// 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); }
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; }
|