Windows2003-3790/inetsrv/iis/admin/common/objpick.cpp
2020-09-30 16:53:55 +02:00

788 lines
22 KiB
C++

// objpick.cpp: implementation of the CGetUser class and the
// CGetComputer class using the object picker
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <iads.h>
#include <objsel.h>
#include <adshlp.h>
#include <winsock2.h>
#include <comdef.h>
#include "common.h"
#include "objpick.h"
#include "accentry.h"
#include "util.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define BREAK_ON_FAIL_HRESULT(hr) \
if (FAILED(hr)) { TRACE(_T("line %u err 0x%x\n"), __LINE__, hr); break; }
UINT g_cfDsObjectPicker; // = ::RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
HRESULT InitObjectPickerForGroups(IDsObjectPicker *pDsObjectPicker,
BOOL fMultiselect,
LPCTSTR pszMachineName,
BOOL bUsersOnly);
HRESULT InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker);
CAccessEntryArray::~CAccessEntryArray()
{
for (int i = 0; i < GetSize(); i++)
delete GetAt(i);
}
//////////////////////////////////////////////////////////////////////
// CGetUsers Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void
FormatName(LPCTSTR pszFullName, LPCTSTR pszDomainName, CString & strDisplay)
{
strDisplay.Format(_T("%s\\%s"), pszDomainName, pszFullName);
}
CGetUsers::CGetUsers(LPCTSTR pszMachineName, BOOL fMultiselect)
: m_MachineName(pszMachineName),
m_fMultiselect(fMultiselect)
{
}
CGetUsers::~CGetUsers()
{
}
BOOL
CGetUsers::GetUsers(HWND hwndParent, BOOL bUsersOnly)
{
HRESULT hr = S_OK;
IDsObjectPicker * pDsObjectPicker = NULL;
IDataObject * pdo = NULL;
BOOL fSuccess = TRUE;
hr = CoInitialize(NULL);
if (FAILED(hr))
return FALSE;
do
{
//
// Create an instance of the object picker. The implementation in
// objsel.dll is apartment model.
//
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &pDsObjectPicker);
BREAK_ON_FAIL_HRESULT(hr);
hr = InitObjectPickerForGroups(pDsObjectPicker, m_fMultiselect, m_MachineName, bUsersOnly);
BREAK_ON_FAIL_HRESULT(hr);
//
// Invoke the modal dialog.
//
hr = pDsObjectPicker->InvokeDialog(hwndParent, &pdo);
BREAK_ON_FAIL_HRESULT(hr);
//
// If the user hit Cancel, hr == S_FALSE
//
if (hr == S_FALSE)
{
TRACE(_T("User canceled object picker dialog\n"));
fSuccess = FALSE;
break;
}
//
// Process the user's selections
//
ASSERT(pdo);
ProcessSelectedObjects(pdo);
pdo->Release();
pdo = NULL;
} while (0);
if (pDsObjectPicker)
{
pDsObjectPicker->Release();
}
CoUninitialize();
if (FAILED(hr) || S_FALSE == hr)
fSuccess = FALSE;
return fSuccess;
}
void
CGetUsers::ProcessSelectedObjects(IDataObject *pdo)
{
HRESULT hr = S_OK;
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
if (g_cfDsObjectPicker == 0)
g_cfDsObjectPicker = ::RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
ASSERT(g_cfDsObjectPicker != 0);
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
BOOL fGotStgMedium = FALSE;
do
{
hr = pdo->GetData(&formatetc, &stgmedium);
BREAK_ON_FAIL_HRESULT(hr);
fGotStgMedium = TRUE;
PDS_SELECTION_LIST pDsSelList =
(PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pDsSelList)
{
TRACE(_T("GlobalLock error %u\n"), GetLastError());
break;
}
// create the path name thing
IADsPathname * pIADsPathname;
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
IID_IADsPathname, (PVOID *)&pIADsPathname);
BREAK_ON_FAIL_HRESULT(hr);
if (FAILED(hr = pIADsPathname->SetDisplayType(ADS_DISPLAY_VALUE_ONLY)))
{
pIADsPathname->Release();
break;
}
for (UINT i = 0; i < pDsSelList->cItems; i++)
{
PSID psid = NULL;
DS_SELECTION * pDsSel = &(pDsSelList->aDsSelection[i]);
if (pDsSel->pvarFetchedAttributes != NULL)
{
hr = SafeArrayAccessData(V_ARRAY(pDsSel->pvarFetchedAttributes), &psid);
}
if (psid != NULL)
{
LPWSTR pwzADsPath = pDsSel->pwzADsPath;
if (FAILED(hr = pIADsPathname->Set(pwzADsPath, ADS_SETTYPE_FULL)))
continue;
long lnNumPathElements = 0;
if (FAILED(hr = pIADsPathname->GetNumElements(&lnNumPathElements)))
continue;
BSTR bstrUser = NULL, bstrDomain = NULL;
if (FAILED(hr = pIADsPathname->GetElement(0, &bstrUser)))
continue;
switch (lnNumPathElements)
{
case 1:
hr = pIADsPathname->Retrieve(ADS_FORMAT_SERVER, &bstrDomain);
break;
case 2: // nt4, nt5 domain
case 3: // local domain
hr = pIADsPathname->GetElement(1, &bstrDomain);
break;
default:
ASSERT(FALSE);
hr = E_FAIL;
}
if (FAILED(hr))
continue;
CString name;
FormatName(bstrUser, bstrDomain, name);
if (bstrDomain != NULL)
SysFreeString(bstrDomain);
if (bstrUser != NULL)
SysFreeString(bstrUser);
CAccessEntry * entry =
new CAccessEntry(psid, name, pDsSel->pwzClass);
Add(entry);
}
}
pIADsPathname->Release();
GlobalUnlock(stgmedium.hGlobal);
} while (0);
if (fGotStgMedium)
{
ReleaseStgMedium(&stgmedium);
}
}
//////////////////////////////////////////////////////////////////////
// CGetComputer Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGetComputer::CGetComputer()
{
}
CGetComputer::~CGetComputer()
{
}
BOOL
CGetComputer::GetComputer(HWND hwndParent)
{
HRESULT hr = S_OK;
IDsObjectPicker * pDsObjectPicker = NULL;
IDataObject * pdo = NULL;
BOOL fSuccess = TRUE;
hr = CoInitialize(NULL);
if (FAILED(hr))
return FALSE;
do
{
//
// Create an instance of the object picker. The implementation in
// objsel.dll is apartment model.
//
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &pDsObjectPicker);
BREAK_ON_FAIL_HRESULT(hr);
//
// Reinitialize the object picker to choose computers
//
hr = InitObjectPickerForComputers(pDsObjectPicker);
BREAK_ON_FAIL_HRESULT(hr);
//
// Now pick a computer
//
hr = pDsObjectPicker->InvokeDialog(hwndParent, &pdo);
BREAK_ON_FAIL_HRESULT(hr);
//
// If the user hit Cancel, hr == S_FALSE
//
if (hr == S_FALSE)
{
TRACE(_T("User canceled object picker dialog\n"));
fSuccess = FALSE;
break;
}
ASSERT(pdo);
ProcessSelectedObjects(pdo);
pdo->Release();
pdo = NULL;
} while (0);
if (pDsObjectPicker)
{
pDsObjectPicker->Release();
}
CoUninitialize();
if (FAILED(hr))
fSuccess = FALSE;
return fSuccess;
}
void
CGetComputer::ProcessSelectedObjects(IDataObject *pdo)
{
HRESULT hr = S_OK;
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
if (g_cfDsObjectPicker == 0)
g_cfDsObjectPicker = ::RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
ASSERT(g_cfDsObjectPicker != 0);
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
BOOL fGotStgMedium = FALSE;
do
{
hr = pdo->GetData(&formatetc, &stgmedium);
BREAK_ON_FAIL_HRESULT(hr);
fGotStgMedium = TRUE;
PDS_SELECTION_LIST pDsSelList =
(PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pDsSelList)
{
TRACE(_T("GlobalLock error %u\n"), GetLastError());
break;
}
CString strTemp = pDsSelList->aDsSelection[0].pwzName;
if (strTemp.Left(2) == _T("\\\\"))
strTemp = pDsSelList->aDsSelection[0].pwzName[2];
if (ERROR_SUCCESS != ObjPickNameOrIpToHostname(strTemp, m_strComputerName))
{
//we use the name from the object picker if we failed to convert it into hostname
m_strComputerName = strTemp;
}
GlobalUnlock(stgmedium.hGlobal);
} while (0);
if (fGotStgMedium)
{
ReleaseStgMedium(&stgmedium);
}
}
//+--------------------------------------------------------------------------
//
// Function: InitObjectPickerForGroups
//
// Synopsis: Call IDsObjectPicker::Initialize with arguments that will
// set it to allow the user to pick one or more groups.
//
// Arguments: [pDsObjectPicker] - object picker interface instance
//
// Returns: Result of calling IDsObjectPicker::Initialize.
//
// History: 10-14-1998 DavidMun Created
// 1-8-2000 SergeiA Adapted for IIS
//
//---------------------------------------------------------------------------
HRESULT
InitObjectPickerForGroups(IDsObjectPicker *pDsObjectPicker,
BOOL fMultiselect,
LPCTSTR pszMachineName,
BOOL bUsersOnly)
{
//
// Prepare to initialize the object picker.
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 5;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
//
// Target computer scope. This adds a "Look In" entry for the
// target computer. Computer scopes are always treated as
// downlevel (i.e., they use the WinNT provider).
//
aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;
aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS;
aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[0].FilterFlags.flDownlevel |=
// DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS;
DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS;
}
//
// The domain to which the target computer is joined. Note we're
// combining two scope types into flType here for convenience.
//
aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[1].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
aScopeInit[1].flType =
DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
| DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
aScopeInit[1].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[1].FilterFlags.Uplevel.flNativeModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE;
}
aScopeInit[1].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[1].FilterFlags.Uplevel.flMixedModeOnly |= DSOP_FILTER_GLOBAL_GROUPS_SE;
}
aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[1].FilterFlags.flDownlevel |= DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS;
}
//
// The domains in the same forest (enterprise) as the domain to which
// the target machine is joined. Note these can only be DS-aware
//
aScopeInit[2].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[2].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN;
aScopeInit[2].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
aScopeInit[2].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[2].FilterFlags.Uplevel.flNativeModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE;
}
aScopeInit[2].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[2].FilterFlags.Uplevel.flMixedModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE;
}
//
// Domains external to the enterprise but trusted directly by the
// domain to which the target machine is joined.
//
// If the target machine is joined to an NT4 domain, only the
// external downlevel domain scope applies, and it will cause
// all domains trusted by the joined domain to appear.
//
aScopeInit[3].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[3].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
aScopeInit[3].flType =
DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
| DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN;
aScopeInit[3].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[3].FilterFlags.Uplevel.flNativeModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE;
}
aScopeInit[3].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[3].FilterFlags.Uplevel.flMixedModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE;
}
aScopeInit[3].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[3].FilterFlags.flDownlevel |=
DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS;
}
//
// The Global Catalog
//
aScopeInit[4].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[4].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
aScopeInit[4].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG;
// Only native mode applies to gc scope.
aScopeInit[4].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS;
if (!bUsersOnly)
{
aScopeInit[4].FilterFlags.Uplevel.flNativeModeOnly |=
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE;
}
//
// Put the scope init array into the object picker init array
//
DSOP_INIT_INFO InitInfo;
ZeroMemory(&InitInfo, sizeof(InitInfo));
InitInfo.cbSize = sizeof(InitInfo);
//
// 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 = pszMachineName;
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
InitInfo.flOptions = (fMultiselect) ? DSOP_FLAG_MULTISELECT : 0;
LPCTSTR attrs[] = {_T("ObjectSid")};
InitInfo.cAttributesToFetch = sizeof(attrs) / sizeof(attrs[0]);
InitInfo.apwzAttributeNames = attrs;
//
// Note object picker makes its own copy of InitInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
HRESULT hr = pDsObjectPicker->Initialize(&InitInfo);
#ifdef _DEBUG
if (FAILED(hr))
{
ULONG i;
for (i = 0; i < SCOPE_INIT_COUNT; i++)
{
if (FAILED(InitInfo.aDsScopeInfos[i].hr))
{
TRACE(_T("Initialization failed because of scope %u\n"), i);
}
}
}
#endif
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: InitObjectPickerForComputers
//
// Synopsis: Call IDsObjectPicker::Initialize with arguments that will
// set it to allow the user to pick a single computer object.
//
// Arguments: [pDsObjectPicker] - object picker interface instance
//
// Returns: Result of calling IDsObjectPicker::Initialize.
//
// History: 10-14-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker)
{
//
// Prepare to initialize the object picker.
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 2;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
//
// Build a scope init struct for everything except the joined domain.
//
aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[0].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
| DSOP_SCOPE_TYPE_GLOBAL_CATALOG
| DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
| DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN
| DSOP_SCOPE_TYPE_WORKGROUP
| DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE
| DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE;
aScopeInit[0].FilterFlags.Uplevel.flBothModes =
DSOP_FILTER_COMPUTERS;
aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
//
// scope for the joined domain, make it the default
//
aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[1].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
| DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
aScopeInit[1].FilterFlags.Uplevel.flBothModes =
DSOP_FILTER_COMPUTERS;
aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
aScopeInit[1].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
//
// Put the scope init array into the object picker init array
//
DSOP_INIT_INFO InitInfo;
ZeroMemory(&InitInfo, sizeof(InitInfo));
InitInfo.cbSize = sizeof(InitInfo);
InitInfo.pwzTargetComputer = NULL; // NULL == local machine
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
//
// Note object picker makes its own copy of InitInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
return pDsObjectPicker->Initialize(&InitInfo);
}
//Convert any valid name of a machine (IP address, NetBios name or fully qualified DNS name)
//to the host name
DWORD ObjPickNameOrIpToHostname(CString & strNameOrIp, CString & strHostName)
{
DWORD dwErr = ERROR_SUCCESS;
CString strTemp;
CIPAddress ia(strNameOrIp);
if (!ia.IsValid())
{
dwErr = MyGetHostName((DWORD)ia, strTemp);
}
else
{
// just want the host name
int nDot = strNameOrIp.Find('.');
if (nDot != -1)
{
strTemp = strNameOrIp.Left(nDot);
}
else
{
strTemp = strNameOrIp;
}
}
if (ERROR_SUCCESS == dwErr)
{
strHostName = strTemp;
}
return dwErr;
}
BOOL
GetIUsrAccount(
IN LPCTSTR lpstrServer,
IN CWnd * pParent, OPTIONAL
OUT CString & str
)
/*++
Routine Description:
Helper function to browse for IUSR Account
Arguments:
LPCTSTR lpstrServer : Server
CWnd * pParent : Parent window
CString & str : Will contain the selected account
Return Value:
TRUE if an account was selected FALSE if not
--*/
{
CGetUsers usrBrowser(lpstrServer);
BOOL bRes = usrBrowser.GetUsers(pParent->GetSafeHwnd(), TRUE);
if (bRes)
{
if (usrBrowser.GetSize() != 0)
{
str = usrBrowser.GetAt(0)->QueryUserName();
}
else
bRes = FALSE;
}
return bRes;
}
BOOL
GetIUsrAccount(
LPCTSTR lpstrServer,
CWnd * pParent,
TCHAR * pBuffer,
int size
)
/*++
Routine Description:
Helper function to browse for IUSR Account
Arguments:
LPCTSTR lpstrServer : Server
CWnd * pParent : Parent window
CString & str : Will contain the selected account
Return Value:
TRUE if an account was selected FALSE if not
--*/
{
CGetUsers usrBrowser(lpstrServer);
BOOL bRes = usrBrowser.GetUsers(pParent->GetSafeHwnd(), TRUE);
if (bRes)
{
if (usrBrowser.GetSize() != 0)
{
lstrcpyn(pBuffer, usrBrowser.GetAt(0)->QueryUserName(), size - 1);
}
else
bRes = FALSE;
}
return bRes;
}