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.
506 lines
16 KiB
506 lines
16 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|