Leaked source code of windows server 2003
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.
 
 
 
 
 
 

4211 lines
116 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: dsUtil.cpp
//
// Contents: Utility functions
//
// History: 08-Nov-99 JeffJon Created
//
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include "dsutil.h"
#include "dssnap.h"
#include "gsz.h"
#include "helpids.h"
#include "querysup.h"
#include "wininet.h"
#include <dnsapi.h>
#include <objsel.h>
#include <ntldap.h> // LDAP_MATCHING_RULE_BIT_AND_W
#include <lmaccess.h> // UF_SERVER_TRUST_ACCOUNT
#include <ntdsapi.h> // DsRemoveDsServer
#include <ntsecapi.h> // Lsa*
UINT g_cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
//
// Common DS strings
//
PCWSTR g_pszAllowedAttributesEffective = L"allowedAttributesEffective";
PCWSTR g_pszPwdLastSet = L"pwdLastSet";
//+-------------------------------------------------------------------------
//
// Function: GetServerFromLDAPPath
//
// Synopsis: Gets the server portion of an LDAP Path
//
// In:
// LPCWSTR - pointer to string to convert
//
// Out:
// BSTR* - pointer to a BSTR containing the server name
//
// Return:
// HRESULT - whether the operation completed successfully
//
//--------------------------------------------------------------------------
HRESULT GetServerFromLDAPPath(IN LPCWSTR lpszLdapPath, OUT BSTR* pbstrServerName)
{
if (pbstrServerName == NULL)
{
return E_POINTER;
}
else if (*pbstrServerName != NULL)
{
::SysFreeString(*pbstrServerName);
*pbstrServerName = NULL;
}
CPathCracker pathCracker;
HRESULT hr = pathCracker.Set(CComBSTR(lpszLdapPath), ADS_SETTYPE_FULL);
RETURN_IF_FAILED(hr);
return pathCracker.Retrieve(ADS_FORMAT_SERVER, pbstrServerName);
}
BOOL
StripADsIPath(
LPCWSTR lpszPath,
CString& strref,
bool bUseEscapedMode /* = true */)
{
CPathCracker pathCracker;
return StripADsIPath(lpszPath, strref, pathCracker, bUseEscapedMode);
}
BOOL
StripADsIPath(
LPCWSTR lpszPath,
CString& strref,
CPathCracker& pathCracker,
bool bUseEscapedMode /* = true */)
{
if (lpszPath == NULL)
{
strref = L"";
return FALSE;
}
if (wcslen(lpszPath) == 0)
{
strref = lpszPath;
return FALSE;
}
if ( bUseEscapedMode )
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_ON);
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
HRESULT hr = pathCracker.Set(CComBSTR(lpszPath), ADS_SETTYPE_FULL);
if (FAILED(hr))
{
TRACE(_T("StripADsIPath, IADsPathname::Set returned error 0x%x\n"), hr);
strref = lpszPath;
return FALSE;
}
CComBSTR bsX500DN;
(void) pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsX500DN);
strref = bsX500DN;
return TRUE;
}
////////////////////////////////////////////////////////////////////////
// support routines for Add To Group function
void RemovePortifPresent(CString *csGroup)
{
CString x, y;
int n = csGroup->Find (L":3268");
if (n > 0) {
x = csGroup->Left(n);
y = csGroup->Right(csGroup->GetLength() - (n+5));
*csGroup = x+y;
}
}
#if (FALSE)
HRESULT AddDataObjListToGroup(IN CObjectNamesFormatCracker* pNames,
IN HWND hwnd)
{
HRESULT hr = S_OK;
TRACE (_T("CDSContextMenu::AddToGroup\n"));
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
// algorithm
// examine selection, figure out classes
// figure out what groups are possible
// call object picker, get a group
// for each object in selection
// if container
// procees_container()
// else
// process_leaf()
//
//
// Create an instance of the object picker.
//
IDsObjectPicker * pDsObjectPicker = NULL;
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &pDsObjectPicker);
if (FAILED(hr))
return(hr);
//
// Prepare to initialize the object picker.
//
// first, get the name of DC that we are talking to.
CComBSTR bstrDC;
LPCWSTR lpszPath = pNames->GetName(0);
GetServerFromLDAPPath(lpszPath, &bstrDC);
//
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 1;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
int scopeindex = 0;
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
//
//
// The domain to which the target computer is joined. Note we're
// combining two scope types into flType here for convenience.
//
aScopeInit[scopeindex].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[scopeindex].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN;
aScopeInit[scopeindex].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
aScopeInit[scopeindex].FilterFlags.Uplevel.flNativeModeOnly =
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE
| DSOP_FILTER_GLOBAL_GROUPS_DL
| DSOP_FILTER_UNIVERSAL_GROUPS_DL
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL
| DSOP_FILTER_BUILTIN_GROUPS;
aScopeInit[scopeindex].FilterFlags.Uplevel.flMixedModeOnly =
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE
| DSOP_FILTER_GLOBAL_GROUPS_DL
| DSOP_FILTER_UNIVERSAL_GROUPS_DL
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL
| DSOP_FILTER_BUILTIN_GROUPS;
aScopeInit[scopeindex].pwzDcName = bstrDC;
//
// 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 = bstrDC;
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
InitInfo.flOptions = 0;
//
// Note object picker makes its own copy of InitInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
hr = pDsObjectPicker->Initialize(&InitInfo);
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);
}
}
ReportErrorEx (hwnd, IDS_OBJECT_PICKER_INIT_FAILED, hr,
MB_OK | MB_ICONERROR, NULL, 0);
return hr;
}
IDataObject *pdo = NULL;
//
// Invoke the modal dialog.
//
hr = pDsObjectPicker->InvokeDialog(hwnd, &pdo);
if (FAILED(hr))
return(hr);
//
// If the user hit Cancel, hr == S_FALSE
//
if (hr == S_FALSE)
return hr;
hr = pdo->GetData(&formatetc, &stgmedium);
if (FAILED(hr))
return hr;
PDS_SELECTION_LIST pSelList =
(PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pSelList)
{
ReleaseStgMedium(&stgmedium);
TRACE(_T("GlobalLock error %u\n"), GetLastError());
//
// REVIEW_JEFFJON : should probably put some kind of error message
// here even though we ignore the return value
//
return E_FAIL;
}
if (pDsObjectPicker)
{
pDsObjectPicker->Release();
}
/////////////////////////////////////////////////////////////
UINT index;
DWORD cModified = 0;
CString csClass;
CString objDN;
IDirectoryObject * pObj = NULL;
INT answer = IDYES;
BOOL error = FALSE;
BOOL partial_success = FALSE;
CWaitCursor CWait;
CString csPath;
if (pSelList != NULL)
{
TRACE(_T("AddToGroup: binding to group path is %s\n"), pSelList->aDsSelection[0].pwzADsPath);
CString csGroup = pSelList->aDsSelection[0].pwzADsPath;
RemovePortifPresent(&csGroup);
hr = DSAdminOpenObject(csGroup,
IID_IDirectoryObject,
(void **)&pObj,
FALSE /*bServer*/);
if (FAILED(hr))
{
PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)pSelList->aDsSelection[0].pwzName};
ReportErrorEx (hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
MB_OK | MB_ICONERROR, apv, 1);
goto ExitGracefully;
}
for (index = 0; index < pNames->GetCount(); index++)
{
csPath = pNames->GetName(index);
TRACE(_T("AddToGroup: object path is %s\n"), csPath);
csClass = pNames->GetClass(index);
TRACE(_T("AddToGroup: object class is %s\n"), csClass);
ADS_ATTR_INFO Attrinfo;
ZeroMemory (&Attrinfo, sizeof (ADS_ATTR_INFO));
PADS_ATTR_INFO pAttrs = &Attrinfo;
Attrinfo.pszAttrName = L"member";
Attrinfo.dwADsType = ADSTYPE_DN_STRING;
Attrinfo.dwControlCode = ADS_ATTR_APPEND;
ADSVALUE Value;
pAttrs->pADsValues = &Value;
pAttrs->dwNumValues = 1;
// make sure there's no strange escaping in the path
CComBSTR bstrPath;
CPathCracker pathCracker;
pathCracker.Set((LPTSTR)(LPCTSTR)csPath, ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
pathCracker.Retrieve( ADS_FORMAT_X500, &bstrPath);
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_ON);
StripADsIPath(bstrPath, objDN);
Value.DNString = (LPWSTR)(LPCWSTR)objDN;
Value.dwType = ADSTYPE_DN_STRING;
hr = pObj->SetObjectAttributes(pAttrs, 1, &cModified);
if (FAILED(hr))
{
error = TRUE;
// prep for display by getting obj name
pathCracker.Set((LPWSTR)pNames->GetName(index), ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
CComBSTR ObjName;
pathCracker.GetElement( 0, &ObjName );
PVOID apv[2] = {(BSTR)(LPWSTR)(LPCWSTR)ObjName,
(BSTR)(LPWSTR)(LPCWSTR)pSelList->aDsSelection[0].pwzName};
if ((pNames->GetCount() - index) == 1)
{
ReportErrorEx (hwnd,IDS_12_MEMBER_ADD_FAILED,hr,
MB_OK | MB_ICONERROR, apv, 2);
}
else
{
int answer1;
answer1 = ReportErrorEx (hwnd,IDS_12_MULTI_MEMBER_ADD_FAILED,hr,
MB_YESNO | MB_ICONERROR, apv, 2);
if (answer1 == IDNO)
{
answer = IDCANCEL;
}
}
}
else
{
partial_success = TRUE;
}
if (answer == IDCANCEL)
{
goto ExitGracefully;
}
}
ExitGracefully:
if( error )
{
if (partial_success == TRUE)
{
ReportErrorEx (hwnd, IDS_ADDTOGROUP_OPERATION_PARTIALLY_COMPLETED, S_OK,
MB_OK | MB_ICONINFORMATION, NULL, 0);
}
else
{
ReportErrorEx (hwnd, IDS_ADDTOGROUP_OPERATION_FAILED, S_OK,
MB_OK | MB_ICONINFORMATION, NULL, 0);
}
}
else if( partial_success == TRUE )
{
ReportErrorEx (hwnd, IDS_ADDTOGROUP_OPERATION_COMPLETED, S_OK,
MB_OK | MB_ICONINFORMATION, NULL, 0);
}
else
{
//else we did nothing and appropriate messages are shown already
ReportErrorEx (hwnd, IDS_ADDTOGROUP_OPERATION_FAILED, S_OK,
MB_OK | MB_ICONINFORMATION, NULL, 0);
}
if (pObj)
{
pObj->Release();
}
}
// NTRAID#NTBUG9-701373-2002/09/09-artm
GlobalUnlock(stgmedium.hGlobal);
ReleaseStgMedium(&stgmedium);
return hr;
}
#endif
HRESULT AddDataObjListToGroup(IN CObjectNamesFormatCracker* pNames,
IN HWND hwnd,
IN CDSComponentData* pComponentData)
{
HRESULT hr = S_OK;
TRACE (_T("CDSContextMenu::AddToGroup\n"));
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
// algorithm
// examine selection, figure out classes
// figure out what groups are possible
// call object picker, get a group
// for each object in selection
// if container
// procees_container()
// else
// process_leaf()
//
//
// Create an instance of the object picker.
//
// NTRAID#NTBUG9-639455-2002/06/13-artm
CComPtr<IDsObjectPicker> pDsObjectPicker;
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &pDsObjectPicker);
if (FAILED(hr))
return(hr);
//
// Prepare to initialize the object picker.
//
// first, get the name of DC that we are talking to.
CComBSTR bstrDC;
LPCWSTR lpszPath = pNames->GetName(0);
GetServerFromLDAPPath(lpszPath, &bstrDC);
//
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 1;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
int scopeindex = 0;
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
//
//
// The domain to which the target computer is joined. Note we're
// combining two scope types into flType here for convenience.
//
aScopeInit[scopeindex].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[scopeindex].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN;
aScopeInit[scopeindex].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS |
DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
aScopeInit[scopeindex].FilterFlags.Uplevel.flNativeModeOnly =
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_UNIVERSAL_GROUPS_SE
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE
| DSOP_FILTER_GLOBAL_GROUPS_DL
| DSOP_FILTER_UNIVERSAL_GROUPS_DL
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL
| DSOP_FILTER_BUILTIN_GROUPS;
aScopeInit[scopeindex].FilterFlags.Uplevel.flMixedModeOnly =
DSOP_FILTER_GLOBAL_GROUPS_SE
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE
| DSOP_FILTER_GLOBAL_GROUPS_DL
| DSOP_FILTER_UNIVERSAL_GROUPS_DL
| DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL
| DSOP_FILTER_BUILTIN_GROUPS;
aScopeInit[scopeindex].pwzDcName = bstrDC;
//
// 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 = bstrDC;
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
InitInfo.flOptions = 0;
//
// Note object picker makes its own copy of InitInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
hr = pDsObjectPicker->Initialize(&InitInfo);
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);
}
}
ReportErrorEx (hwnd, IDS_OBJECT_PICKER_INIT_FAILED, hr,
MB_OK | MB_ICONERROR, NULL, 0);
return hr;
}
IDataObject *pdo = NULL;
//
// Invoke the modal dialog.
//
hr = pDsObjectPicker->InvokeDialog(hwnd, &pdo);
//
// If the user hit Cancel, hr == S_FALSE
//
if (SUCCEEDED(hr) && hr != S_FALSE)
{
ASSERT(pdo); // Should never happen, indicates bug in object picker.
hr = pdo->GetData(&formatetc, &stgmedium);
}
// NTRAID#NTBUG9-639455-2002/06/26-artm
if (pdo)
{
pdo->Release();
pdo = NULL;
}
if (FAILED(hr) || hr == S_FALSE)
{
return hr;
}
PDS_SELECTION_LIST pSelList =
(PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pSelList)
{
ReleaseStgMedium(&stgmedium);
TRACE(_T("GlobalLock error %u\n"), GetLastError());
//
// REVIEW_JEFFJON : should probably put some kind of error message
// here even though we ignore the return value
//
return E_FAIL;
}
hr = AddDataObjListToGivenGroup(pNames,
pSelList->aDsSelection[0].pwzADsPath,
pSelList->aDsSelection[0].pwzName,
hwnd,
pComponentData);
// NTRAID#NTBUG9-701373-2002/09/09-artm
GlobalUnlock(stgmedium.hGlobal);
ReleaseStgMedium(&stgmedium);
return hr;
}
HRESULT AddDataObjListToGivenGroup(CObjectNamesFormatCracker * pNames,
LPCWSTR lpszGroupLDapPath,
LPCWSTR lpszGroupName,
HWND hwnd,
CDSComponentData* pComponentData)
{
HRESULT hr = S_OK;
UINT index = 0;
DWORD cModified = 0;
CString csClass;
CString objDN;
IDirectoryObject * pObj = NULL;
BOOL error = FALSE;
BOOL partial_success = FALSE;
CWaitCursor CWait;
CString csPath;
//
// Prepare error structures for use with the multi-operation error dialog
// These arrays may not be completely full depending on the number of errors
// that occurr
//
PWSTR* pErrorArray = new PWSTR[pNames->GetCount()];
if (!pErrorArray)
{
return E_OUTOFMEMORY;
}
memset(pErrorArray, 0, pNames->GetCount() * sizeof(PWSTR));
PWSTR* pPathArray = new PWSTR[pNames->GetCount()];
if (!pPathArray)
{
return E_OUTOFMEMORY;
}
memset(pPathArray, 0, pNames->GetCount() * sizeof(PWSTR));
PWSTR* pClassArray = new PWSTR[pNames->GetCount()];
if (!pClassArray)
{
return E_OUTOFMEMORY;
}
memset(pClassArray, 0, pNames->GetCount() * sizeof(PWSTR));
UINT nErrorCount = 0;
TRACE(_T("AddToGroup: binding to group path is %s\n"), lpszGroupLDapPath);
CString csGroup = lpszGroupLDapPath;
RemovePortifPresent(&csGroup);
hr = DSAdminOpenObject(csGroup,
IID_IDirectoryObject,
(void **)&pObj,
FALSE /*bServer*/);
if (FAILED(hr))
{
PVOID apv[1] = {(BSTR)(LPWSTR)lpszGroupName};
ReportErrorEx (hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
MB_OK | MB_ICONERROR, apv, 1);
error = TRUE;
goto ExitGracefully;
}
for (index = 0; index < pNames->GetCount(); index++)
{
// make sure there's no strange escaping in the path
CComBSTR bstrDN;
csPath = pNames->GetName(index);
TRACE(_T("AddToGroup: object path is %s\n"), csPath);
csClass = pNames->GetClass(index);
TRACE(_T("AddToGroup: object class is %s\n"), csClass);
ADS_ATTR_INFO Attrinfo;
ZeroMemory (&Attrinfo, sizeof (ADS_ATTR_INFO));
PADS_ATTR_INFO pAttrs = &Attrinfo;
Attrinfo.pszAttrName = L"member";
Attrinfo.dwADsType = ADSTYPE_DN_STRING;
Attrinfo.dwControlCode = ADS_ATTR_APPEND;
ADSVALUE Value;
pAttrs->pADsValues = &Value;
pAttrs->dwNumValues = 1;
CPathCracker pathCracker;
pathCracker.Set(CComBSTR(csPath), ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
pathCracker.Retrieve( ADS_FORMAT_X500_DN, &bstrDN);
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_ON);
objDN = bstrDN;
Value.DNString = (LPWSTR)(LPCWSTR)objDN;
Value.dwType = ADSTYPE_DN_STRING;
hr = pObj->SetObjectAttributes(pAttrs, 1, &cModified);
if (FAILED(hr))
{
error = TRUE;
if (pNames->GetCount() > 1)
{
if (pErrorArray != NULL &&
pPathArray != NULL &&
pClassArray != NULL)
{
PWSTR pszErrMessage = 0;
int iChar = cchLoadHrMsg(hr, &pszErrMessage, TRUE);
if (pszErrMessage != NULL && iChar > 0)
{
//
// this is a hack to get rid of two extra characters
// at the end of the error message
//
size_t iLen = wcslen(pszErrMessage);
//NTRAID#NTBUG9-571998-2002/03/10-jmessec possible underflow, not localization friendly
pszErrMessage[iLen - 2] = L'\0';
pErrorArray[nErrorCount] = new WCHAR[wcslen(pszErrMessage) + 1];
if (pErrorArray[nErrorCount] != NULL)
{
wcscpy(pErrorArray[nErrorCount], pszErrMessage);
}
LocalFree(pszErrMessage);
}
pPathArray[nErrorCount] = new WCHAR[wcslen(objDN) + 1];
if (pPathArray[nErrorCount] != NULL)
{
wcscpy(pPathArray[nErrorCount], objDN);
}
pClassArray[nErrorCount] = new WCHAR[wcslen(csClass) + 1];
if (pClassArray[nErrorCount] != NULL)
{
wcscpy(pClassArray[nErrorCount], csClass);
}
nErrorCount++;
}
}
else
{
//
// prep for display by getting obj name
//
CPathCracker pathCrackerToo;
pathCrackerToo.Set(CComBSTR(pNames->GetName(index)), ADS_SETTYPE_FULL);
pathCrackerToo.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
CComBSTR ObjName;
pathCrackerToo.GetElement( 0, &ObjName );
PVOID apv[2] = {(BSTR)(LPWSTR)(LPCWSTR)ObjName,
(BSTR)(LPWSTR)lpszGroupName};
ReportErrorEx (hwnd,IDS_12_MEMBER_ADD_FAILED,hr,
MB_OK | MB_ICONERROR, apv, 2);
}
}
else
{
partial_success = TRUE;
}
} // for
ExitGracefully:
if (nErrorCount > 0 && pNames->GetCount() > 1)
{
//
// Load the strings for the error dialog
//
CString szTitle;
if (pComponentData->QuerySnapinType() == SNAPINTYPE_SITE)
{
VERIFY(szTitle.LoadString(IDS_SITESNAPINNAME));
}
else
{
VERIFY(szTitle.LoadString(IDS_DSSNAPINNAME));
}
CString szCaption;
VERIFY(szCaption.LoadString(IDS_MULTI_ADDTOGROUP_ERROR_CAPTION));
CString szHeader;
VERIFY(szHeader.LoadString(IDS_COLUMN_NAME));
CThemeContextActivator activator;
CMultiselectErrorDialog errDialog(pComponentData);
VERIFY(SUCCEEDED(errDialog.Initialize(pPathArray,
pClassArray,
pErrorArray,
nErrorCount,
szTitle,
szCaption,
szHeader)));
errDialog.DoModal();
}
else if (nErrorCount == 0 && !error)
{
ReportErrorEx (hwnd, IDS_ADDTOGROUP_OPERATION_COMPLETED, S_OK,
MB_OK | MB_ICONINFORMATION, NULL, 0);
}
else
{
//
// Do nothing if it was single select and there was a failure
// The error should have already been reported.
//
}
if (pObj)
{
pObj->Release();
}
if (pErrorArray != NULL)
{
for (UINT nIdx = 0; nIdx < pNames->GetCount(); nIdx++)
{
if (pErrorArray[nIdx] != NULL)
{
delete[] pErrorArray[nIdx];
}
}
delete[] pErrorArray;
pErrorArray = NULL;
}
if (pPathArray != NULL)
{
for (UINT nIdx = 0; nIdx < pNames->GetCount(); nIdx++)
{
if (pPathArray[nIdx] != NULL)
{
delete[] pPathArray[nIdx];
}
}
delete[] pPathArray;
pPathArray = NULL;
}
if (pClassArray != NULL)
{
for (UINT nIdx = 0; nIdx < pNames->GetCount(); nIdx++)
{
if (pClassArray[nIdx] != NULL)
{
delete[] pClassArray[nIdx];
}
}
delete[] pClassArray;
pClassArray = NULL;
}
return hr;
}
// NTRAID#NTBUG9-472020-2002/01/16-ronmart-added comment block
/*******************************************************************
NAME: IsValidSiteName
SYNOPSIS: Calls DnsValidateName to determine if the specified
site name meets both size and format requirements
RETURNS: (BOOL) TRUE if a valid site name, else FALSE. Callers
can provide out flag pointers to learn more about
the result of its internal call to DnsValidName
NOTE: pfNonRfc is an optional out param that is set when
DnsValidName fails because the name isn't RFC
compliant. This function will still return TRUE
because the caller can ignore this case, but it should
typically check this value and prompt the user to
continue.
pfInvalidNameChar is an optional out param that is
set when DnsValidateName fails because the site name
contains an invalid character.
HISTORY:
ronmart 16-Jan-2002 Added pfInvalidNameChar support
********************************************************************/
BOOL IsValidSiteName( LPCTSTR lpctszSiteName, BOOL* pfNonRfc, BOOL* pfInvalidNameChar )
{
if (NULL != pfNonRfc)
*pfNonRfc = FALSE;
if (NULL == lpctszSiteName)
return FALSE;
if (NULL != wcschr( lpctszSiteName, _T('.') ))
{
// NTRAID#NTBUG9-472020-2002/01/16-ronmart-set invalid char to display proper error message
if(NULL != pfInvalidNameChar)
*pfInvalidNameChar = TRUE;
return FALSE;
}
// NTRAID#NTBUG9-472020-2002/01/16-ronmart-Changed from DnsValidateDnsName to DnsValidateName
// with DnsNameDomainLabel flag. The old method was a macro that mapped to DnsValidateName
// with DnsNameDomain as the 2nd param.
DWORD dw = ::DnsValidateName_W( const_cast<LPTSTR>(lpctszSiteName), DnsNameDomainLabel );
switch (dw)
{
// NTRAID#NTBUG9-472020-2002/01/16-ronmart-If invalid char then fail and let the caller
// know why so a proper error message can be displayed
case DNS_ERROR_INVALID_NAME_CHAR:
if (NULL != pfInvalidNameChar)
*pfInvalidNameChar = TRUE;
return FALSE;
case DNS_ERROR_NON_RFC_NAME:
if (NULL != pfNonRfc)
*pfNonRfc = TRUE;
break;
case DNS_ERROR_RCODE_NO_ERROR:
break;
default:
return FALSE;
}
return TRUE;
}
/*******************************************************************
NAME: GetAuthenticationID
SYNOPSIS: Retrieves the UserName associated with the credentials
currently being used for network access.
(runas /netonly credentials)
RETURNS: A win32 error code
NOTE: String returned must be freed with LocalFree
HISTORY:
JeffreyS 05-Aug-1999 Created
Modified by hiteshr to return credentials
JeffJon 21-Nov-2000 Modified to return a win32 error
********************************************************************/
ULONG
GetAuthenticationID(LPWSTR *ppszResult)
{
ULONG ulReturn = 0;
HANDLE hLsa;
NTSTATUS Status = 0;
*ppszResult = NULL;
//
// These LSA calls are delay-loaded from secur32.dll using the linker's
// delay-load mechanism. Therefore, wrap with an exception handler.
//
__try
{
Status = LsaConnectUntrusted(&hLsa);
if (Status == 0)
{
NEGOTIATE_CALLER_NAME_REQUEST Req = {0};
PNEGOTIATE_CALLER_NAME_RESPONSE pResp;
ULONG cbSize =0;
NTSTATUS SubStatus =0;
Req.MessageType = NegGetCallerName;
Status = LsaCallAuthenticationPackage(
hLsa,
0,
&Req,
sizeof(Req),
(void**)&pResp,
&cbSize,
&SubStatus);
if ((Status == 0) && (SubStatus == 0))
{
LocalAllocString(ppszResult,pResp->CallerName);
LsaFreeReturnBuffer(pResp);
}
LsaDeregisterLogonProcess(hLsa);
}
ulReturn = LsaNtStatusToWinError(Status);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return ulReturn;
}
// IsLocalLogin
//Function determines if the user has logged in as
//Local user or to a domain
BOOL IsLocalLogin( void )
{
DWORD nSize = 0;
PWSTR pszUserName = NULL;
if (ERROR_SUCCESS != GetAuthenticationID(&pszUserName))
return false;
CString strSamComName( pszUserName );
int nPos = strSamComName.Find('\\');
if( -1 == nPos ){
LocalFree(pszUserName);
return false;
}
CString strDomainOrLocalName( strSamComName.Mid(0,nPos) );
WCHAR lpszName1[ MAX_COMPUTERNAME_LENGTH + 1 ];
nSize = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName( lpszName1, &nSize);
CString strCompName ( (LPCWSTR)lpszName1 );
LocalFree(pszUserName);
return ( strDomainOrLocalName == strCompName );
}
// IsThisUserLoggedIn
//Function determines if the user is the same as the
//passed in DN.
//Parameter is either a DN or a full ADSI path
extern LPWSTR g_lpszLoggedInUser = NULL;
BOOL IsThisUserLoggedIn( LPCTSTR pwszUserDN )
{
DWORD nSize = 0;
BOOL result = FALSE;
if (g_lpszLoggedInUser == NULL) {
//get the size passing null pointer
GetUserNameEx(NameFullyQualifiedDN , NULL, &nSize);
if( nSize == 0 )
return false;
g_lpszLoggedInUser = new WCHAR[ nSize ];
if( g_lpszLoggedInUser == NULL )
return false;
GetUserNameEx(NameFullyQualifiedDN, g_lpszLoggedInUser, &nSize );
}
CString csUserDN = pwszUserDN;
CString csDN;
(void) StripADsIPath(csUserDN, csDN);
if (!_wcsicmp (g_lpszLoggedInUser, csDN)) {
result = TRUE;
}
return result;
}
//+---------------------------------------------------------------------------
//
// Function: SetSecurityInfoMask
//
// Synopsis: Reads the security descriptor from the specied DS object
//
// Arguments: [IN punk] -- IUnknown from IDirectoryObject
// [IN si] -- SecurityInformation
//// History: 25-Dec-2000 -- Hiteshr Created
//----------------------------------------------------------------------------
HRESULT
SetSecurityInfoMask(LPUNKNOWN punk, SECURITY_INFORMATION si)
{
HRESULT hr = E_INVALIDARG;
if (punk)
{
IADsObjectOptions *pOptions;
hr = punk->QueryInterface(IID_IADsObjectOptions, (void**)&pOptions);
if (SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_I4;
V_I4(&var) = si;
hr = pOptions->SetOption(ADS_OPTION_SECURITY_MASK, var);
pOptions->Release();
}
}
return hr;
}
WCHAR const c_szSDProperty[] = L"nTSecurityDescriptor";
//+---------------------------------------------------------------------------
//
// Function: DSReadObjectSecurity
//
// Synopsis: Reads the Dacl from the specied DS object
//
// Arguments: [in pDsObject] -- IDirettoryObject for dsobject
// [psdControl] -- Control Setting for SD
// They can be returned when calling
// DSWriteObjectSecurity
// [OUT ppDacl] -- DACL returned here
//
//
// History 25-Oct-2000 -- hiteshr created
//
// Notes: If Object Doesn't have DACL, function will succeed but *ppDacl will
// be NULL.
// Caller must free *ppDacl, if not NULL, by calling LocalFree
//
//----------------------------------------------------------------------------
HRESULT
DSReadObjectSecurity(IN IDirectoryObject *pDsObject,
OUT SECURITY_DESCRIPTOR_CONTROL * psdControl,
OUT PACL *ppDacl)
{
HRESULT hr = S_OK;
PADS_ATTR_INFO pSDAttributeInfo = NULL;
do // false loop
{
LPWSTR pszSDProperty = (LPWSTR)c_szSDProperty;
DWORD dwAttributesReturned;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pAcl = NULL;
if(!pDsObject || !ppDacl)
{
ASSERT(FALSE);
hr = E_INVALIDARG;
break;
}
*ppDacl = NULL;
// Set the SECURITY_INFORMATION mask
hr = SetSecurityInfoMask(pDsObject, DACL_SECURITY_INFORMATION);
if(FAILED(hr))
{
break;
}
//
// Read the security descriptor
//
hr = pDsObject->GetObjectAttributes(&pszSDProperty,
1,
&pSDAttributeInfo,
&dwAttributesReturned);
if (SUCCEEDED(hr) && !pSDAttributeInfo)
hr = E_ACCESSDENIED; // This happens for SACL if no SecurityPrivilege
if(FAILED(hr))
{
break;
}
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->dwADsType);
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->pADsValues->dwType);
pSD = (PSECURITY_DESCRIPTOR)pSDAttributeInfo->pADsValues->SecurityDescriptor.lpValue;
ASSERT(IsValidSecurityDescriptor(pSD));
//
//Get the security descriptor control
//
if(psdControl)
{
DWORD dwRevision;
if(!GetSecurityDescriptorControl(pSD, psdControl, &dwRevision))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
}
//
//Get pointer to DACL
//
BOOL bDaclPresent, bDaclDefaulted;
if(!GetSecurityDescriptorDacl(pSD,
&bDaclPresent,
&pAcl,
&bDaclDefaulted))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
if(!bDaclPresent ||
!pAcl)
{
break;
}
ASSERT(IsValidAcl(pAcl));
//
//Make a copy of the DACL
//
*ppDacl = (PACL)LocalAlloc(LPTR,pAcl->AclSize);
if(!*ppDacl)
{
hr = E_OUTOFMEMORY;
break;
}
CopyMemory(*ppDacl,pAcl,pAcl->AclSize);
}while(0);
if (pSDAttributeInfo)
FreeADsMem(pSDAttributeInfo);
return hr;
}
const GUID GUID_CONTROL_UserChangePassword =
{ 0xab721a53, 0x1e2f, 0x11d0, { 0x98, 0x19, 0x00, 0xaa, 0x00, 0x40, 0x52, 0x9b}};
bool CanUserChangePassword(IN IDirectoryObject* pDirObject)
{
bool bCanChangePassword = false;
HRESULT hr = S_OK;
do // false loop
{
//
// Validate parameters
//
if (!pDirObject)
{
ASSERT(pDirObject);
break;
}
SECURITY_DESCRIPTOR_CONTROL sdControl = {0};
CSimpleAclHolder Dacl;
hr = DSReadObjectSecurity(pDirObject,
&sdControl,
&(Dacl.m_pAcl));
if (FAILED(hr))
{
break;
}
//
// Create and Initialize the Self and World SIDs
//
CSidHolder selfSid;
CSidHolder worldSid;
PSID pSid = NULL;
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY,
WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
if (!AllocateAndInitializeSid(&NtAuth,
1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pSid))
{
break;
}
selfSid.Attach(pSid, false);
pSid = NULL;
if (!AllocateAndInitializeSid(&WorldAuth,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pSid))
{
break;
}
worldSid.Attach(pSid, false);
pSid = NULL;
ULONG ulCount = 0, j = 0;
PEXPLICIT_ACCESS rgEntries = NULL;
DWORD dwErr = GetExplicitEntriesFromAcl(Dacl.m_pAcl, &ulCount, &rgEntries);
if (ERROR_SUCCESS != dwErr)
{
break;
}
//
// Are these ACEs already present?
//
bool bSelfAllowPresent = false;
bool bWorldAllowPresent = false;
bool bSelfDenyPresent = false;
bool bWorldDenyPresent = false;
//
// Loop through looking for the can change password ACE for self and world
//
for (j = 0; j < ulCount; j++)
{
//
// Look for deny ACEs
//
if ((rgEntries[j].Trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_SID) &&
(rgEntries[j].grfAccessMode == DENY_ACCESS))
{
OBJECTS_AND_SID* pObjectsAndSid = NULL;
pObjectsAndSid = (OBJECTS_AND_SID*)rgEntries[j].Trustee.ptstrName;
//
// Look for the user can change password ACE
//
if (IsEqualGUID(pObjectsAndSid->ObjectTypeGuid,
GUID_CONTROL_UserChangePassword))
{
//
// See if it is for the self SID or the world SID
//
if (EqualSid(pObjectsAndSid->pSid, selfSid.Get()))
{
//
// Deny self found
//
bSelfDenyPresent = true;
}
else if (EqualSid(pObjectsAndSid->pSid, worldSid.Get()))
{
//
// Deny world found
//
bWorldDenyPresent = true;
}
}
}
//
// Look for allow ACEs
//
else if ((rgEntries[j].Trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_SID) &&
(rgEntries[j].grfAccessMode == GRANT_ACCESS))
{
OBJECTS_AND_SID* pObjectsAndSid = NULL;
pObjectsAndSid = (OBJECTS_AND_SID*)rgEntries[j].Trustee.ptstrName;
//
// Look for the user can change password ACE
//
if (IsEqualGUID(pObjectsAndSid->ObjectTypeGuid,
GUID_CONTROL_UserChangePassword))
{
//
// See if it is for the self SID or the world SID
//
if (EqualSid(pObjectsAndSid->pSid, selfSid.Get()))
{
//
// Allow self found
//
bSelfAllowPresent = true;
}
else if (EqualSid(pObjectsAndSid->pSid, worldSid.Get()))
{
//
// Allow world found
//
bWorldAllowPresent = true;
}
}
}
}
if (bSelfDenyPresent || bWorldDenyPresent)
{
//
// There is an explicit deny so we know that the user cannot change password
//
bCanChangePassword = false;
}
else if ((!bSelfDenyPresent && !bWorldDenyPresent) &&
(bSelfAllowPresent || bWorldAllowPresent))
{
//
// There is no explicit deny but there are explicit allows so we know that
// the user can change password
//
bCanChangePassword = true;
}
else
{
//
// We are not sure because the explicit entries are not telling us for
// certain so it all depends on inheritence. Most likely they will
// be able to change their password unless the admin has changed something
// higher up or through group membership
//
bCanChangePassword = true;
}
} while(false);
return bCanChangePassword;
}
/////////////////////////////////////////////////////////////////////////////////
// CDSNotifyDataObject
class CDSNotifyDataObject : public IDataObject, public CComObjectRoot
{
// ATL Maps
DECLARE_NOT_AGGREGATABLE(CDSNotifyDataObject)
BEGIN_COM_MAP(CDSNotifyDataObject)
COM_INTERFACE_ENTRY(IDataObject)
END_COM_MAP()
// Construction/Destruction
CDSNotifyDataObject()
{
m_dwFlags = 0;
m_dwProviderFlags = 0;
m_pCLSIDNamespace = NULL;
}
~CDSNotifyDataObject() {}
// Standard IDataObject methods
public:
// Implemented
STDMETHOD(GetData)(FORMATETC * pformatetcIn, STGMEDIUM * pmedium);
// Not Implemented
private:
STDMETHOD(GetDataHere)(FORMATETC*, STGMEDIUM*) { return E_NOTIMPL; };
STDMETHOD(EnumFormatEtc)(DWORD, IEnumFORMATETC**) { return E_NOTIMPL; };
STDMETHOD(SetData)(FORMATETC*, STGMEDIUM*, BOOL) { return E_NOTIMPL; };
STDMETHOD(QueryGetData)(FORMATETC*) { return E_NOTIMPL; };
STDMETHOD(GetCanonicalFormatEtc)(FORMATETC*, FORMATETC*) { return E_NOTIMPL; };
STDMETHOD(DAdvise)(FORMATETC*, DWORD, IAdviseSink*, DWORD*) { return E_NOTIMPL; };
STDMETHOD(DUnadvise)(DWORD) { return E_NOTIMPL; };
STDMETHOD(EnumDAdvise)(IEnumSTATDATA**) { return E_NOTIMPL; };
public:
// Property Page Clipboard formats
static CLIPFORMAT m_cfDsObjectNames;
// initialization
HRESULT Init(LPCWSTR lpszPath, LPCWSTR lpszClass, BOOL bContainer,
CDSComponentData* pCD);
// Implementation
private:
CString m_szPath;
CString m_szClass;
DWORD m_dwFlags;
DWORD m_dwProviderFlags;
const CLSID* m_pCLSIDNamespace;
};
CLIPFORMAT CDSNotifyDataObject::m_cfDsObjectNames =
(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
STDMETHODIMP CDSNotifyDataObject::GetData(FORMATETC * pFormatEtc, STGMEDIUM * pMedium)
{
if ((pFormatEtc == NULL) || (pMedium == NULL))
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pMedium, sizeof(STGMEDIUM)))
{
return E_INVALIDARG;
}
if (!(pFormatEtc->tymed & TYMED_HGLOBAL))
{
return DV_E_TYMED;
}
// we support only one clipboard format
pMedium->tymed = TYMED_HGLOBAL;
pMedium->pUnkForRelease = NULL;
if (pFormatEtc->cfFormat != m_cfDsObjectNames)
{
return DV_E_FORMATETC;
}
// figure out how much storage we need
int nPathLen = m_szPath.GetLength();
int nClassLen = m_szClass.GetLength();
int cbStruct = sizeof(DSOBJECTNAMES); //contains already a DSOBJECT embedded struct
DWORD cbStorage = (nPathLen + 1 + nClassLen + 1) * sizeof(WCHAR);
LPDSOBJECTNAMES pDSObj;
pDSObj = (LPDSOBJECTNAMES)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
cbStruct + cbStorage);
if (pDSObj == NULL)
{
return STG_E_MEDIUMFULL;
}
// write the info
pDSObj->clsidNamespace = *m_pCLSIDNamespace;
pDSObj->cItems = 1;
pDSObj->aObjects[0].dwFlags = m_dwFlags;
pDSObj->aObjects[0].dwProviderFlags = m_dwProviderFlags;
pDSObj->aObjects[0].offsetName = cbStruct;
pDSObj->aObjects[0].offsetClass = cbStruct + (nPathLen + 1) * sizeof(WCHAR);
_tcscpy((LPTSTR)((BYTE *)pDSObj + (pDSObj->aObjects[0].offsetName)), (LPCWSTR)m_szPath);
_tcscpy((LPTSTR)((BYTE *)pDSObj + (pDSObj->aObjects[0].offsetClass)), (LPCWSTR)m_szClass);
pMedium->hGlobal = (HGLOBAL)pDSObj;
return S_OK;
}
HRESULT CDSNotifyDataObject::Init(LPCWSTR lpszPath, LPCWSTR lpszClass, BOOL bContainer,
CDSComponentData* pCD)
{
m_szPath = lpszPath;
m_szClass = lpszClass;
switch (pCD->QuerySnapinType())
{
case SNAPINTYPE_DS:
m_pCLSIDNamespace = &CLSID_DSSnapin;
break;
case SNAPINTYPE_SITE:
m_pCLSIDNamespace = &CLSID_SiteSnapin;
break;
default:
m_pCLSIDNamespace = &CLSID_NULL;
}
m_dwProviderFlags = (pCD->IsAdvancedView()) ? DSPROVIDER_ADVANCED : 0;
m_dwFlags = bContainer ? DSOBJECT_ISCONTAINER : 0;
return S_OK;
}
/////////////////////////////////////////////////////////////////////
// CChangePasswordPrivilegeAction
static GUID UserChangePasswordGUID =
{ 0xab721a53, 0x1e2f, 0x11d0, { 0x98, 0x19, 0x00, 0xaa, 0x00, 0x40, 0x52, 0x9b}};
HRESULT CChangePasswordPrivilegeAction::Load(IADs * pIADs)
{
// reset state, just in case
m_bstrObjectLdapPath = (LPCWSTR)NULL;
m_pDacl = NULL;
m_SelfSid.Clear();
m_WorldSid.Clear();
// get the full LDAP path of the object
HRESULT hr = pIADs->get_ADsPath(&m_bstrObjectLdapPath);
ASSERT (SUCCEEDED(hr));
if (FAILED(hr))
{
TRACE(_T("failed on pIADs->get_ADsPath()\n"));
return hr;
}
// allocate SIDs
hr = _SetSids();
if (FAILED(hr))
{
TRACE(_T("failed on _SetSids()\n"));
return hr;
}
// read info
TRACE(_T("GetSDForDsObjectPath(%s)\n"), m_bstrObjectLdapPath);
DWORD dwErr =
::GetDsObjectSD(
m_bstrObjectLdapPath,
&(m_pDacl),
&(m_SDHolder.m_pSD));
TRACE(L"GetDsObjectSD() returned dwErr = 0x%x\n", dwErr);
if (dwErr != ERROR_SUCCESS)
{
TRACE(L"GetDsObjectSD() failed!\n");
return HRESULT_FROM_WIN32(dwErr);
}
return S_OK;
}
HRESULT CChangePasswordPrivilegeAction::Read(BOOL* pbPasswordCannotChange)
{
*pbPasswordCannotChange = FALSE;
// find about the existence of the deny ACEs
ULONG ulCount, j;
PEXPLICIT_ACCESS rgEntries;
ASSERT(m_pDacl);
DWORD dwErr = GetExplicitEntriesFromAcl(m_pDacl, &ulCount, &rgEntries);
TRACE(L"GetExplicitEntriesFromAcl() returned dwErr = 0x%x\n", dwErr);
if (dwErr != ERROR_SUCCESS)
{
TRACE(L"GetExplicitEntriesFromAcl() failed!\n");
return HRESULT_FROM_WIN32(dwErr);
}
for (j = 0; j < ulCount; j++)
{
if ((rgEntries[j].Trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_SID) &&
(rgEntries[j].grfAccessMode == DENY_ACCESS))
{
OBJECTS_AND_SID * pObjectsAndSid;
pObjectsAndSid = (OBJECTS_AND_SID *)rgEntries[j].Trustee.ptstrName;
if (IsEqualGUID(pObjectsAndSid->ObjectTypeGuid,
UserChangePasswordGUID) &&
(EqualSid(pObjectsAndSid->pSid, m_SelfSid.Get()) ||
EqualSid(pObjectsAndSid->pSid, m_WorldSid.Get())))
{
*pbPasswordCannotChange = TRUE;
} // if
} // if
} // for
TRACE(L"*pbPasswordCannotChange = %d\n", *pbPasswordCannotChange);
return S_OK;
}
HRESULT CChangePasswordPrivilegeAction::Revoke()
{
DWORD dwErr = 0;
EXPLICIT_ACCESS rgAccessEntry[2] = {0};
OBJECTS_AND_SID rgObjectsAndSid[2] = {0};
// initialize the entries (DENY ACE's)
rgAccessEntry[0].grfAccessPermissions = ACTRL_DS_CONTROL_ACCESS;
rgAccessEntry[0].grfAccessMode = DENY_ACCESS;
rgAccessEntry[0].grfInheritance = NO_INHERITANCE;
rgAccessEntry[1].grfAccessPermissions = ACTRL_DS_CONTROL_ACCESS;
rgAccessEntry[1].grfAccessMode = DENY_ACCESS;
rgAccessEntry[1].grfInheritance = NO_INHERITANCE;
// build the trustee structs for change password
BuildTrusteeWithObjectsAndSid(&(rgAccessEntry[0].Trustee),
&(rgObjectsAndSid[0]),
&UserChangePasswordGUID,
NULL, // inherit guid
m_SelfSid.Get()
);
BuildTrusteeWithObjectsAndSid(&(rgAccessEntry[1].Trustee),
&(rgObjectsAndSid[1]),
&UserChangePasswordGUID,
NULL, // inherit guid
m_WorldSid.Get()
);
// add the entries to the ACL
TRACE(L"calling SetEntriesInAcl()\n");
CSimpleAclHolder NewDacl;
dwErr = ::SetEntriesInAcl(2, rgAccessEntry, m_pDacl, &(NewDacl.m_pAcl));
TRACE(L"SetEntriesInAcl() returned dwErr = 0x%x\n", dwErr);
if (dwErr != ERROR_SUCCESS)
{
TRACE(_T("SetEntriesInAccessList failed!\n"));
return HRESULT_FROM_WIN32(dwErr);
}
// commit the changes
TRACE(L"calling SetDsObjectDacl()\n");
dwErr =
::SetDsObjectDacl(
(LPCWSTR)(BSTR)m_bstrObjectLdapPath,
NewDacl.m_pAcl);
TRACE(L"SetDsObjectDacl() returned dwErr = 0x%x\n", dwErr);
if (dwErr != ERROR_SUCCESS)
{
TRACE(_T("SetDsObjectDacl() failed!\n"));
return HRESULT_FROM_WIN32(dwErr);
}
return S_OK;
}
HRESULT CChangePasswordPrivilegeAction::_SetSids()
{
PSID pSidTemp;
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY,
WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
//
// build SID's for Self and World.
//
if (!AllocateAndInitializeSid(&NtAuth,
1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pSidTemp))
{
TRACE(_T("AllocateAndInitializeSid failed!\n"));
return HRESULT_FROM_WIN32(GetLastError());
}
m_SelfSid.Attach(pSidTemp, FALSE);
if (!AllocateAndInitializeSid(&WorldAuth,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pSidTemp))
{
TRACE(_T("AllocateAndInitializeSid failed!\n"));
return HRESULT_FROM_WIN32(GetLastError());
}
m_WorldSid.Attach(pSidTemp, FALSE);
return S_OK;
}
/////////////////////////////////////////////////////////////////////
// CDSNotifyHandlerTransaction
CDSNotifyHandlerTransaction::CDSNotifyHandlerTransaction(CDSComponentData* pCD)
{
m_bStarted = FALSE;
m_uEvent = 0;
m_pCD = pCD;
if (m_pCD != NULL)
{
m_pMgr = pCD->GetNotifyHandlerManager();
ASSERT(m_pMgr != NULL);
}
}
UINT CDSNotifyHandlerTransaction::NeedNotifyCount()
{
if ((m_pCD == NULL) || (m_pMgr == NULL))
return 0; // we have no handler for doing notifications
if (!m_pMgr->HasHandlers())
return 0;
return m_pMgr->NeedNotifyCount(m_uEvent);
}
void CDSNotifyHandlerTransaction::SetCheckListBox(CCheckListBox* pCheckListBox)
{
if ((m_pCD == NULL) || (m_pMgr == NULL))
return; // we have no handler for doing notifications
ASSERT(m_pMgr->HasHandlers());
m_pMgr->SetCheckListBox(pCheckListBox, m_uEvent);
}
void CDSNotifyHandlerTransaction::ReadFromCheckListBox(CCheckListBox* pCheckListBox)
{
if ((m_pCD == NULL) || (m_pMgr == NULL))
return; // we have no handler for doing notifications
ASSERT(m_pMgr->HasHandlers());
m_pMgr->ReadFromCheckListBox(pCheckListBox, m_uEvent);
}
HRESULT CDSNotifyHandlerTransaction::Begin(LPCWSTR lpszArg1Path,
LPCWSTR lpszArg1Class,
BOOL bArg1Cont,
LPCWSTR lpszArg2Path,
LPCWSTR lpszArg2Class,
BOOL bArg2Cont)
{
m_bStarted = TRUE;
ASSERT(m_uEvent != 0);
m_spArg1 = NULL;
m_spArg2 = NULL;
if ((m_pCD == NULL) || (m_pMgr == NULL))
{
return S_OK; // we have no handler for doing notifications
}
//
// if needed, do delayed message handler initialization
//
m_pMgr->Load(m_pCD->GetBasePathsInfo());
//
// avoid building data objects if there are no handlers available
//
if (!m_pMgr->HasHandlers())
{
return S_OK;
}
//
// build first argument data object
//
HRESULT hr = _BuildDataObject(lpszArg1Path, lpszArg1Class, bArg1Cont, &m_spArg1);
if (FAILED(hr))
{
return hr;
}
//
// if needed, build second argument
//
if ( (m_uEvent == DSA_NOTIFY_MOV) || (m_uEvent == DSA_NOTIFY_REN) )
{
hr = _BuildDataObject(lpszArg2Path, lpszArg2Class, bArg2Cont, &m_spArg2);
if (FAILED(hr))
{
return hr;
}
}
m_pMgr->Begin(m_uEvent, m_spArg1, m_spArg2);
return S_OK;
}
HRESULT CDSNotifyHandlerTransaction::Begin(CDSCookie* pArg1Cookie,
LPCWSTR lpszArg2Path,
LPCWSTR lpszArg2Class,
BOOL bArg2Cont)
{
m_bStarted = TRUE;
ASSERT(m_uEvent != 0);
if ((m_pCD == NULL) || (m_pMgr == NULL))
{
return S_OK; // we have no handler for doing notifications
}
//
// get info from the node and cookie and call the other Begin() function
//
CString szPath;
m_pCD->GetBasePathsInfo()->ComposeADsIPath(szPath, pArg1Cookie->GetPath());
return Begin(szPath, pArg1Cookie->GetClass(), pArg1Cookie->IsContainerClass(),
lpszArg2Path, lpszArg2Class, bArg2Cont);
}
HRESULT CDSNotifyHandlerTransaction::Begin(IDataObject* pArg1,
LPCWSTR lpszArg2Path,
LPCWSTR lpszArg2Class,
BOOL bArg2Cont)
{
m_bStarted = TRUE;
ASSERT(m_uEvent != 0);
m_spArg1 = NULL;
m_spArg2 = NULL;
HRESULT hr;
if ((m_pCD == NULL) || (m_pMgr == NULL))
{
return S_OK; // we have no handler for doing notifications
}
//
// if needed, do delayed message handler initialization
//
m_pMgr->Load(m_pCD->GetBasePathsInfo());
//
// avoid building data objects if there are no handlers available
//
if (!m_pMgr->HasHandlers())
{
return S_OK;
}
//
// get the first argument as is
//
m_spArg1 = pArg1;
//
// if needed, build second argument
//
if ( (m_uEvent != DSA_NOTIFY_DEL) && (m_uEvent != DSA_NOTIFY_PROP) )
{
hr = _BuildDataObject(lpszArg2Path, lpszArg2Class, bArg2Cont, &m_spArg2);
if (FAILED(hr))
{
return hr;
}
}
m_pMgr->Begin(m_uEvent, m_spArg1, m_spArg2);
return S_OK;
}
void CDSNotifyHandlerTransaction::Notify(ULONG nItem)
{
ASSERT(m_bStarted);
ASSERT(m_uEvent != 0);
if ((m_pCD == NULL) || (m_pMgr == NULL) || !m_pMgr->HasHandlers())
return;
m_pMgr->Notify(nItem, m_uEvent);
}
void CDSNotifyHandlerTransaction::End()
{
ASSERT(m_bStarted);
ASSERT(m_uEvent != 0);
if ((m_pCD == NULL) || (m_pMgr == NULL) || !m_pMgr->HasHandlers())
return;
m_pMgr->End(m_uEvent);
m_spArg1 = NULL;
m_spArg2 = NULL;
m_bStarted = FALSE;
}
HRESULT CDSNotifyHandlerTransaction::BuildTransactionDataObject(LPCWSTR lpszArgPath,
LPCWSTR lpszArgClass,
BOOL bContainer,
CDSComponentData* pCD,
IDataObject** ppArg)
{
(*ppArg) = NULL;
ASSERT((lpszArgPath != NULL) && (lpszArgPath[0] != NULL));
ASSERT((lpszArgClass != NULL) && (lpszArgClass[0] != NULL));
//
// need to build a data object and hang on to it
//
CComObject<CDSNotifyDataObject>* pObject;
CComObject<CDSNotifyDataObject>::CreateInstance(&pObject);
if (pObject == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pObject->FinalConstruct();
if (FAILED(hr))
{
delete pObject;
return hr;
}
hr = pObject->Init(lpszArgPath, lpszArgClass, bContainer, pCD);
if (FAILED(hr))
{
delete pObject;
return hr;
}
hr = pObject->QueryInterface(IID_IDataObject,
reinterpret_cast<void**>(ppArg));
if (FAILED(hr))
{
//
// delete object by calling Release()
//
(*ppArg)->Release();
(*ppArg) = NULL;
return hr;
}
return hr;
}
HRESULT CDSNotifyHandlerTransaction::_BuildDataObject(LPCWSTR lpszArgPath,
LPCWSTR lpszArgClass,
BOOL bContainer,
IDataObject** ppArg)
{
ASSERT(m_uEvent != 0);
ASSERT(m_pCD != NULL);
return BuildTransactionDataObject(lpszArgPath, lpszArgClass,bContainer, m_pCD, ppArg);
}
/*
// JonN 6/2/00 99382
// SITEREPL: Run interference when administrator attempts to
// delete critical object (NTDS Settings)
// reports own errors, returns true iff deletion should proceed
bool CUIOperationHandlerBase::CheckForNTDSDSAInSubtree(
LPCTSTR lpszX500Path,
LPCTSTR lpszItemName)
{
if (NULL == GetComponentData())
{
ASSERT(FALSE);
return false;
}
// set up subtree search
CDSSearch Search(GetComponentData()->GetClassCache(), GetComponentData());
CString strRootPath;
GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(strRootPath, lpszX500Path);
HRESULT hr = Search.Init(strRootPath);
// retrieve X500DN path to schema container
CString strSchemaPath;
GetComponentData()->GetBasePathsInfo()->GetSchemaPath(strSchemaPath);
CPathCracker pathCracker;
pathCracker.Set(const_cast<LPTSTR>((LPCTSTR)strSchemaPath),
ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
CComBSTR sbstrSchemaPathX500DN;
pathCracker.Retrieve(ADS_FORMAT_X500_DN,&sbstrSchemaPathX500DN);
// filter search
CString strFilter;
strFilter = L"(|(objectCategory=CN=NTDS-DSA,";
strFilter += sbstrSchemaPathX500DN;
strFilter += L")(&(objectCategory=CN=Computer,";
strFilter += sbstrSchemaPathX500DN;
strFilter += L")(userAccountControl:" LDAP_MATCHING_RULE_BIT_AND_W L":=8192)))";
Search.SetFilterString((LPWSTR)(LPCWSTR)strFilter);
Search.SetSearchScope(ADS_SCOPE_SUBTREE);
LPWSTR pAttrs[2] = {L"objectClass",
L"distinguishedName"};
Search.SetAttributeList (pAttrs, 2);
hr = Search.DoQuery();
if (SUCCEEDED(hr))
hr = Search.GetNextRow();
CString strX500PathDC;
while (SUCCEEDED(hr) && hr != S_ADS_NOMORE_ROWS)
{
ADS_SEARCH_COLUMN Column;
hr = Search.GetColumn (pAttrs[1], &Column);
if (FAILED(hr) || Column.dwNumValues < 1) break;
strX500PathDC = Column.pADsValues[Column.dwNumValues-1].CaseIgnoreString;
Search.FreeColumn(&Column);
if (lstrcmpi(lpszX500Path,strX500PathDC))
break;
// This is the object being deleted, this check does not apply here.
// Continue the search.
hr = Search.GetNextRow();
}
if (hr == S_ADS_NOMORE_ROWS)
return true;
else if (FAILED(hr))
return true; // CODEWORK do we want to allow this operation to proceed?
// retrieve the name of the DC
CComBSTR sbstrDCName;
bool fFoundNTDSDSA = FALSE;
ADS_SEARCH_COLUMN Column;
hr = Search.GetColumn (pAttrs[0], &Column);
if (SUCCEEDED(hr) && Column.dwNumValues > 0)
{
fFoundNTDSDSA = !lstrcmpi( L"nTDSDSA",
Column.pADsValues[Column.dwNumValues-1].CaseIgnoreString );
Search.FreeColumn(&Column);
pathCracker.Set((LPWSTR)(LPCWSTR)strX500PathDC, ADS_SETTYPE_DN);
pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
pathCracker.GetElement( (fFoundNTDSDSA)?1:0, &sbstrDCName );
}
// display an error message
PVOID apv[2] = {(PVOID)lpszItemName, (PVOID)(LPCTSTR)sbstrDCName};
(void) ReportErrorEx(GetParentHwnd(),IDS_12_CONTAINS_DC,hr,
MB_ICONERROR, apv, 2);
// do not proceed with subtree deletion
return false;
}
*/
//////////////////////////////////////////////////////////////////////////////////
// CheckForCriticalSystemObjectInSubtree
//
// description:
// This function does a subtree search of the container that is passed in looking
// for all objects that have isCriticalSystemObject=TRUE or NTDS Settings objects.
//
// parameters:
// lpszX500Path - (IN) the X500 path of the container in which to search for
// critical system objects
// lpszItemName - (IN) the displayable name of the container in which to search
// for critical system objects
//
// return value:
// true - The container does not contain any critical system objects
// false - The container does contain at least on critical system object
//////////////////////////////////////////////////////////////////////////////////
bool CUIOperationHandlerBase::CheckForCriticalSystemObjectInSubtree(
LPCTSTR lpszX500Path,
LPCTSTR lpszItemName)
{
bool bRet = true;
if (NULL == GetComponentData())
{
ASSERT(FALSE);
return false;
}
CString szCriticalObjPath;
// set up subtree search
CDSSearch Search(GetComponentData()->GetClassCache(), GetComponentData());
HRESULT hr = Search.Init(lpszX500Path);
if (FAILED(hr))
{
ASSERT(FALSE && L"Failed to set the path in the search object");
return false;
}
//
// retrieve X500DN path to schema container
//
CString strSchemaPath;
GetComponentData()->GetBasePathsInfo()->GetSchemaPath(strSchemaPath);
CPathCracker pathCracker;
pathCracker.Set(CComBSTR(strSchemaPath),
ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
CComBSTR sbstrSchemaPathX500DN;
pathCracker.Retrieve(ADS_FORMAT_X500_DN,&sbstrSchemaPathX500DN);
//
// filter search
//
CString strFilter;
strFilter = L"(|(&(objectClass=*)(isCriticalSystemObject=TRUE))";
strFilter += L"(|(objectCategory=CN=NTDS-DSA,";
strFilter += sbstrSchemaPathX500DN;
//
// 212232 JonN 10/27/00 Protect interSiteTransport objects
//
strFilter += L")(objectCategory=CN=Inter-Site-Transport,";
strFilter += sbstrSchemaPathX500DN;
strFilter += L")(&(objectCategory=CN=Computer,";
strFilter += sbstrSchemaPathX500DN;
strFilter += L")(userAccountControl:" LDAP_MATCHING_RULE_BIT_AND_W L":=8192))))";
Search.SetFilterString((LPWSTR)(LPCWSTR)strFilter);
Search.SetSearchScope(ADS_SCOPE_SUBTREE);
LPWSTR pAttrs[4] = { L"aDSPath",
L"objectClass",
L"distinguishedName",
L"isCriticalSystemObject"};
Search.SetAttributeList (pAttrs, 4);
hr = Search.DoQuery();
if (SUCCEEDED(hr))
{
hr = Search.GetNextRow();
}
if (hr == S_ADS_NOMORE_ROWS)
{
return true;
}
while (SUCCEEDED(hr) && hr != S_ADS_NOMORE_ROWS)
{
ADS_SEARCH_COLUMN PathColumn, CriticalColumn;
hr = Search.GetColumn(pAttrs[3], &CriticalColumn);
if (SUCCEEDED(hr) && CriticalColumn.pADsValues != NULL && CriticalColumn.pADsValues->Boolean)
{
//
// We found a critical system object so report the error and then return
//
hr = Search.GetColumn(pAttrs[0], &PathColumn);
if (SUCCEEDED(hr) && PathColumn.dwNumValues == 1 && PathColumn.pADsValues != NULL)
{
//
// JonN 5/16/01 392582
// DSAdmin: Message IDS_CONTAINS_CRITICALSYSOBJ isn't appropriate
// when the object being deleted and the critical system object
// are one and the same
//
// Allow subtree deletion where the root object is the only one
// marked isCriticalSystemObject
//
if ( !lstrcmpi(lpszX500Path, PathColumn.pADsValues->CaseIgnoreString) )
{
TRACE(_T("CheckForCriticalSystemObjectInSubtree: root is critical\n"));
}
else
{
//
// Get the DN as a Windows style path
//
CComBSTR bstrLeaf;
CPathCracker pathCrackerToo;
HRESULT hrPathCracker = pathCrackerToo.Set(CComBSTR(PathColumn.pADsValues->CaseIgnoreString), ADS_SETTYPE_FULL);
if (SUCCEEDED(hr))
{
hrPathCracker = pathCrackerToo.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
if (SUCCEEDED(hr))
{
hrPathCracker = pathCrackerToo.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
if (SUCCEEDED(hr))
{
hrPathCracker = pathCrackerToo.Retrieve(ADS_FORMAT_LEAF, &bstrLeaf);
}
}
}
//
// display an error message
//
if (wcslen(bstrLeaf))
{
PVOID apv[2] = {(PVOID)lpszItemName, (PVOID)(LPWSTR)bstrLeaf };
(void) ReportErrorEx(GetParentHwnd(),IDS_CONTAINS_CRITICALSYSOBJ,S_OK,
MB_ICONERROR, apv, 2);
}
else
{
PVOID apv[2] = {(PVOID)lpszItemName, (PVOID)PathColumn.pADsValues->CaseIgnoreString };
(void) ReportErrorEx(GetParentHwnd(),IDS_CONTAINS_CRITICALSYSOBJ,S_OK,
MB_ICONERROR, apv, 2);
}
bRet = false;
}
Search.FreeColumn(&PathColumn);
}
Search.FreeColumn(&CriticalColumn);
if (!bRet)
break;
}
else
{
//
// We found an NTDS Settings object. Report the error and return.
//
hr = Search.GetColumn(pAttrs[0], &PathColumn);
if (SUCCEEDED(hr) && PathColumn.dwNumValues == 1 && PathColumn.pADsValues != NULL)
{
CString strX500PathDC = PathColumn.pADsValues[PathColumn.dwNumValues-1].CaseIgnoreString;
Search.FreeColumn(&PathColumn);
if (lstrcmpi(lpszX500Path,strX500PathDC))
{
//
// retrieve the name of the DC
//
CComBSTR sbstrDCName;
bool fFoundNTDSDSA = FALSE;
ADS_SEARCH_COLUMN ClassColumn;
hr = Search.GetColumn (pAttrs[1], &ClassColumn);
if (SUCCEEDED(hr) && ClassColumn.dwNumValues > 0)
{
fFoundNTDSDSA = !lstrcmpi( L"nTDSDSA",
ClassColumn.pADsValues[ClassColumn.dwNumValues-1].CaseIgnoreString );
Search.FreeColumn(&ClassColumn);
pathCracker.Set(CComBSTR(strX500PathDC), ADS_SETTYPE_DN);
pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
pathCracker.GetElement( (fFoundNTDSDSA)?1:0, &sbstrDCName );
}
// display an error message
PVOID apv[2] = {(PVOID)lpszItemName, (PVOID)(LPCTSTR)sbstrDCName};
(void) ReportErrorEx(GetParentHwnd(),IDS_12_CONTAINS_DC,hr,
MB_ICONERROR, apv, 2);
// do not proceed with subtree deletion
bRet = false;
break;
}
}
}
hr = Search.GetNextRow();
}
// do not proceed with subtree deletion
return bRet;
}
/////////////////////////////////////////////////////////////////////
// CDeleteDCDialog
// JonN 12/19/01 267769 removed CDeleteDCDialog help
class CDeleteDCDialog : public CDialog
{
// Construction
public:
CDeleteDCDialog(LPCTSTR lpszName, bool fIsComputer);
// NTRAID#NTBUG9-267769-2001/06/06-lucios - Begin
// JonN 12/19/01 267769 removed CDeleteDCDialog help
// virtual void DoContextHelp(HWND hWndControl);
// NTRAID#NTBUG9-267769-2001/06/06-lucios - End
// Implementation
protected:
// message handlers and MFC overrides
virtual BOOL OnInitDialog();
virtual void OnOK();
DECLARE_MESSAGE_MAP()
private:
CString m_strADsPath;
bool m_fIsComputer;
};
BEGIN_MESSAGE_MAP(CDeleteDCDialog, CDialog)
END_MESSAGE_MAP()
// JonN 12/19/01 267769 removed CDeleteDCDialog help
CDeleteDCDialog::CDeleteDCDialog(LPCTSTR lpszADsPath, bool fIsComputer)
: CDialog(IDD_DELETE_DC_COMPUTER, NULL)
, m_strADsPath(lpszADsPath)
, m_fIsComputer(fIsComputer)
{
}
// NTRAID#NTBUG9-267769-2001/06/06-lucios - Begin
// JonN 12/19/01 267769 removed CDeleteDCDialog help
/*
void CDeleteDCDialog::DoContextHelp(HWND hWndControl)
{
if (hWndControl)
{
::WinHelp(hWndControl,
DSADMIN_CONTEXT_HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_DELETE_DC_COMPUTER);
}
}
*/
// NTRAID#NTBUG9-267769-2001/06/06-lucios - End
BOOL CDeleteDCDialog::OnInitDialog()
{
// CODEWORK AfxInit?
// JonN 12/19/01 267769 removed CDeleteDCDialog help
CDialog::OnInitDialog();
CPathCracker pathCracker;
pathCracker.Set(CComBSTR(m_strADsPath), ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
CString strDisplay;
CComBSTR sbstrName;
if (m_fIsComputer)
{
pathCracker.GetElement( 0, &sbstrName );
strDisplay.FormatMessage(IDS_DELETE_DC_COMPUTERACCOUNT, sbstrName);
}
else
{
CComBSTR sbstrSite;
pathCracker.GetElement( 1, &sbstrName );
pathCracker.GetElement( 3, &sbstrSite );
CString strTemp;
(void) GetDlgItemText(IDC_DELETE_DC_MAINTEXT, strTemp);
strDisplay.FormatMessage( strTemp, sbstrName, sbstrSite );
}
(void) SetDlgItemText( IDC_DELETE_DC_MAINTEXT, strDisplay );
CheckRadioButton( IDC_DELETE_DC_BADREASON1,
IDC_DELETE_DC_GOODREASON,
IDC_DELETE_DC_BADREASON1 );
return TRUE;
}
void CDeleteDCDialog::OnOK()
{
if (BST_CHECKED == IsDlgButtonChecked(IDC_DELETE_DC_GOODREASON))
{
// JonN 12/19/01 267769 removed CDeleteDCDialog help
CDialog::OnOK();
return;
}
(void) ReportErrorEx((HWND)*this,
(BST_CHECKED == IsDlgButtonChecked(IDC_DELETE_DC_BADREASON2))
? IDS_DELETE_DC_BADREASON2
: IDS_DELETE_DC_BADREASON1,
S_OK,MB_OK, NULL, 0);
// JonN 12/19/01 267769 removed CDeleteDCDialog help
CDialog::OnCancel();
}
// JonN 6/15/00 13574
// Centralizes the checks to make sure this is an OK object to delete
// returns HRESULT_FROM_WIN32(ERROR_CANCELLED) on cancellation
// returns refAlreadyDeleted=true iff ObjectDeletionCheck already
// attempted an alternate deletion method (e.g. DsRemoveDsServer).
HRESULT CUIOperationHandlerBase::ObjectDeletionCheck(
LPCTSTR lpszADsPath,
LPCTSTR lpszName, // shortname to display to user, may be NULL
LPCTSTR lpszClass,
bool& fAlternateDeleteMethod )
{
fAlternateDeleteMethod = false;
if (!_wcsicmp(L"user",lpszClass)
#ifdef INETORGPERSON
|| !_wcsicmp(L"inetOrgPerson", lpszClass)
#endif
)
{
if (IsThisUserLoggedIn(lpszADsPath))
{
CComBSTR sbstrRDN;
if (NULL == lpszName)
{
(void) DSPROP_RetrieveRDN( lpszADsPath, &sbstrRDN );
lpszName = sbstrRDN;
}
PVOID apv[1] = {(PVOID)lpszName};
if (IDYES != ReportMessageEx (GetParentHwnd(), IDS_12_USER_LOGGED_IN,
MB_YESNO, apv, 1))
{
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
}
return S_OK;
}
bool fIsComputer = false;
if (!_wcsicmp(L"computer",lpszClass))
{
//
// Bind and figure out if the account is a DC
//
CComPtr<IADs> spIADs;
HRESULT hr = DSAdminOpenObject((LPWSTR)lpszADsPath,
IID_IADs,
(void **)&spIADs);
CComVariant Var;
if (SUCCEEDED(hr))
hr = spIADs->Get(CComBSTR(L"userAccountControl"), &Var);
if ( FAILED(hr) || !(Var.lVal & UF_SERVER_TRUST_ACCOUNT))
return S_OK; // cannot be shown to be a DC
fIsComputer = true;
}
else if (!_wcsicmp(L"nTDSDSA",lpszClass))
{
//
// I would like to figure out the domain name so that I could
// use fCommit==FALSE, but this is a little complicated.
// Basic code is in proppage GetReplicatedDomainInfo(), but
// is not exportable in its current form. I will defer this
// improvement for later.
//
}
else if (!_wcsicmp(L"trustedDomain",lpszClass))
{
//
// Give a strong warning if they are trying to delete a
// TDO (Trusted Domain Object). This could cause serious
// problems but we want to allow them to clean up if necessary
//
PVOID apv[1] = {(PVOID)lpszName};
if (IDYES == ReportMessageEx( GetParentHwnd(),
IDS_WARNING_TDO_DELTEE,
MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING,
apv,
1 ) )
{
fAlternateDeleteMethod = FALSE;
return S_OK;
}
else
{
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
}
else if (!_wcsicmp(L"interSiteTransport",lpszClass))
{
//
// 212232 JonN 10/27/00 Protect interSiteTransport objects
//
PVOID apv[1] = {(PVOID)lpszName};
(void) ReportMessageEx( GetParentHwnd(),
IDS_1_ERROR_DELETE_CRITOBJ,
MB_OK | MB_ICONERROR,
apv,
1 );
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
else
{
return S_OK; // This is neither a computer nor an nTDSDSA nor a TDO
}
// This is either an nTDSDSA object, or a computer object
// which represents a DC
CThemeContextActivator activator;
CDeleteDCDialog dlg(lpszADsPath,fIsComputer);
if (IDOK != dlg.DoModal())
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
if (fIsComputer)
return S_OK;
// This is an nTDSDSA. Delete using DsRemoveDsServer.
fAlternateDeleteMethod = true;
Smart_DsHandle shDS;
BOOL fLastDcInDomain = FALSE;
DWORD dwWinError = DsBind(
m_pComponentData->GetBasePathsInfo()->GetServerName(),
NULL,
&shDS );
if (ERROR_SUCCESS == dwWinError)
{
CPathCracker pathCracker;
pathCracker.Set(CComBSTR(lpszADsPath), ADS_SETTYPE_FULL);
pathCracker.RemoveLeafElement(); // pass DN to Server object
CComBSTR sbstrDN;
pathCracker.Retrieve( ADS_FORMAT_X500_DN, &sbstrDN );
dwWinError = DsRemoveDsServer( shDS,
sbstrDN,
NULL,
&fLastDcInDomain,
TRUE );
}
return HRESULT_FROM_WIN32(dwWinError);
}
///////////////////////////////////////////////////////////////////////////
// CSingleDeleteHandlerBase
/*
NOTICE: the function will return S_OK on success, S_FALSE if aborted
by user, some FAILED(hr) otherwise
*/
HRESULT CSingleDeleteHandlerBase::Delete()
{
CThemeContextActivator activator;
HRESULT hr = S_OK;
bool fAlternateDeleteMethod = false;
// start the transaction
hr = BeginTransaction();
ASSERT(SUCCEEDED(hr));
if (GetTransaction()->NeedNotifyCount() > 0)
{
CString szMessage, szAssocData;
szMessage.LoadString(IDS_CONFIRM_DELETE);
szAssocData.LoadString(IDS_EXTENS_SINGLE_DEL);
CConfirmOperationDialog dlg(GetParentHwnd(), GetTransaction());
dlg.SetStrings(szMessage, szAssocData);
if (IDNO == dlg.DoModal())
{
GetTransaction()->End();
return S_FALSE;
}
}
else
{
// this is just a message box, using ReportErrorEx for consistency of look
UINT answer = ReportErrorEx(GetParentHwnd(),IDS_CONFIRM_DELETE,S_OK,
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2, NULL, 0);
if (answer == IDNO || answer == IDCANCEL) {
return S_FALSE; // aborted by user
}
}
CString szName;
GetItemName(szName);
hr = ObjectDeletionCheck(
GetItemPath(),
szName,
GetItemClass(),
fAlternateDeleteMethod );
if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr)
return S_FALSE; // CODEWORK doesn't end transaction?
else if (FAILED(hr))
return hr; // CODEWORK doesn't end transaction?
// try to delete the object
if (!fAlternateDeleteMethod)
hr = DeleteObject();
if (SUCCEEDED(hr))
{
// item deleted, notify extensions
GetTransaction()->Notify(0);
}
else
{
// error in deleting item, check if it is a special error code
if (hr == HRESULT_FROM_WIN32(ERROR_DS_CANT_ON_NON_LEAF))
{
// ask user to if he/she wants to delete the whole subtree
PVOID apv[1] = {(LPWSTR)(LPCWSTR)szName};
UINT answer = ReportErrorEx(GetParentHwnd(),IDS_12_OBJECT_HAS_CHILDREN,hr,
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2, apv, 1);
if (answer == IDYES)
{
// JonN 5/22/00 Watch for potential NTDSDSA deletion
// JeffJon 8/10/00 Watch for potential critical object deletion (isCriticalSystemObject) bug #27377
//
if (CheckForCriticalSystemObjectInSubtree(GetItemPath(), szName))
{
//
// try to delete the subtree and continue trying if we reach the 16k limit
//
do
{
hr = DeleteSubtree();
} while (HRESULT_CODE(hr) == ERROR_DS_ADMIN_LIMIT_EXCEEDED);
if (SUCCEEDED(hr))
{
GetTransaction()->Notify(0);
}
else
{
// failed subtree deletion, nothing can be done
PVOID apvToo[1] = {(LPWSTR)(LPCWSTR)szName};
ReportErrorEx(GetParentHwnd(), IDS_12_SUBTREE_DELETE_FAILED,hr,
MB_OK | MB_ICONERROR, apvToo, 1);
}
}
}
}
else if (hr == E_ACCESSDENIED)
{
PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)szName};
ReportErrorEx(GetParentHwnd(), IDS_12_DELETE_ACCESS_DENIED, hr,
MB_OK | MB_ICONERROR, apv, 1);
}
else if (HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS)
{
PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)szName};
ReportErrorEx(GetParentHwnd(),IDS_12_DELETE_PRIMARY_GROUP_FAILED,hr,
MB_OK | MB_ICONERROR, apv, 1);
}
else
{
PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)szName};
ReportErrorEx(GetParentHwnd(),IDS_12_DELETE_FAILED,hr,
MB_OK | MB_ICONERROR, apv, 1);
}
}
if (SUCCEEDED(hr))
{
CStringList szDeletedPathList;
szDeletedPathList.AddTail(GetItemPath());
CDSComponentData* pComponentData = GetComponentData();
if (pComponentData)
{
pComponentData->InvalidateSavedQueriesContainingObjects(szDeletedPathList);
}
}
return hr;
GetTransaction()->End();
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CMultipleDeleteHandlerBase
void CMultipleDeleteHandlerBase::Delete()
{
CThemeContextActivator activator;
HRESULT hr = BeginTransaction();
ASSERT(SUCCEEDED(hr));
// ask confirmation to the user
UINT cCookieTotalCount = GetItemCount();
CString szFormat;
szFormat.LoadString(IDS_CONFIRM_MULTI_DELETE);
CString szMessage;
szMessage.Format((LPCWSTR)szFormat, cCookieTotalCount);
if (GetTransaction()->NeedNotifyCount() > 0)
{
CString szAssocData;
szAssocData.LoadString(IDS_EXTENS_MULTIPLE_DEL);
CConfirmOperationDialog dlg(GetParentHwnd(), GetTransaction());
dlg.SetStrings(szMessage, szAssocData);
if (IDNO == dlg.DoModal())
{
GetTransaction()->End();
return;
}
}
else
{
PVOID apv[1] = {(LPWSTR)(LPCWSTR)szMessage};
if (ReportErrorEx(GetParentHwnd(),IDS_STRING,S_OK,
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2,
apv, 1)== IDNO)
{
return; // user aborted
}
}
CMultipleDeleteProgressDialog dlg(GetParentHwnd(), GetComponentData(), this);
dlg.DoModal();
}
void CMultipleDeleteHandlerBase::OnStart(HWND hwnd)
{
SetParentHwnd(hwnd);
m_confirmationUI.SetWindow(GetParentHwnd());
}
HRESULT CMultipleDeleteHandlerBase::OnDeleteStep(IN UINT i,
OUT BOOL* pbContinue,
OUT CString& strrefPath,
OUT CString& strrefClass,
IN BOOL bSilent)
{
ASSERT(i < GetItemCount());
if (pbContinue == NULL)
{
return E_POINTER;
}
//
// Initialize the OUT parameters
//
GetItemPath(i, strrefPath);
strrefClass = GetItemClass(i);
*pbContinue = TRUE;
//
// do the operation
//
HRESULT hr = DeleteObject(i);
if ((SUCCEEDED(hr)))
{
// item deleted, notify extensions and end transaction
GetTransaction()->Notify(i);
OnItemDeleted(i);
}
else
{
CString szName;
GetItemName(i, szName);
// error in deleting item, check if it is a special error code
if (hr == HRESULT_FROM_WIN32(ERROR_DS_CANT_ON_NON_LEAF))
{
// ask confirmation for deleting subtree
if (m_confirmationUI.CanDeleteSubtree(hr, szName, pbContinue))
{
// JeffJon 8/10/00 Watch for potential deletion of critical system objects
if ( !CheckForCriticalSystemObjectInSubtree(strrefPath, szName))
{
// error already reported
*pbContinue = FALSE;
return E_FAIL;
}
//
// Delete the subtree and continue deleting if the 16k limit is reached
//
do
{
hr = DeleteSubtree(i);
} while (hr == ERROR_DS_ADMIN_LIMIT_EXCEEDED);
if (SUCCEEDED(hr))
{
// item deleted, notify extensions and end transaction
GetTransaction()->Notify(i);
OnItemDeleted(i);
}
else
{
// we failed subtree deletion
*pbContinue = m_confirmationUI.ErrorOnSubtreeDeletion(hr, szName);
}
}
else
{
//
// This tells the calling function that we did not delete the object
// but don't add it to the error reporting
//
hr = E_FAIL;
}
}
else
{
// we failed deletion
// JonN 7/20/00 If the HRESULT_FROM_WIN32(ERROR_CANCELLED) case,
// skip the confirmation UI and just cancel the series.
if (bSilent)
{
*pbContinue = hr != HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
else
{
*pbContinue = hr != HRESULT_FROM_WIN32(ERROR_CANCELLED) &&
m_confirmationUI.ErrorOnDeletion(hr, szName);
}
} // if (ERROR_DS_CANT_ON_NON_LEAF)
} // if (delete object)
return hr;
}
//////////////////////////////////////////////////////////////////////////
// CMoveHandlerBase
HRESULT CMoveHandlerBase::Move(LPCWSTR lpszDestinationPath)
{
// make sure destination data is reset
m_spDSDestination = NULL;
m_szDestPath.Empty();
m_szDestClass.Empty();
// check nomber of items
UINT nCount = GetItemCount();
if (nCount == 0)
{
return E_INVALIDARG;
}
// get the info about the destination container
HRESULT hr = _BrowseForDestination(lpszDestinationPath);
if (FAILED(hr) || (hr == S_FALSE))
{
return hr;
}
//
// First check to see if we are trying to move into the same container
// Using the path of the first object in the multiselect case is OK
//
CString szNewPath;
GetNewPath(0, szNewPath);
CPathCracker pathCracker;
hr = pathCracker.Set(CComBSTR(szNewPath), ADS_SETTYPE_FULL);
if (SUCCEEDED(hr))
{
hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
if (SUCCEEDED(hr))
{
hr = pathCracker.RemoveLeafElement();
if (SUCCEEDED(hr))
{
CComBSTR sbstrContainerPath;
hr = pathCracker.Retrieve(ADS_FORMAT_X500, &sbstrContainerPath);
if (SUCCEEDED(hr))
{
if (0 == _wcsicmp(sbstrContainerPath, m_szDestPath))
{
//
// The source and the target container are the same so we
// don't have to do anything
//
return S_OK;
}
}
}
}
}
CStringList szMovedPathList;
for (UINT nIdx = 0; nIdx < GetItemCount(); nIdx++)
{
CString szPath;
GetItemPath(nIdx, szPath);
szMovedPathList.AddTail(szPath);
}
//
// Notice that we fall through on a failure trying to crack the source parent path
// so reset the return value
//
hr = S_OK;
// do the actual move operation
if (nCount == 1)
{
BOOL bContinue = FALSE;
do
{
//
// Check to be sure we are not trying to drop on itself
//
if (m_szDestPath == szNewPath)
{
UINT nRet = ReportErrorEx(GetParentHwnd(), IDS_ERR_MSG_NO_MOVE_TO_SELF, S_OK,
MB_YESNO | MB_ICONERROR, NULL, 0);
if (nRet == IDYES)
{
// get the info about the destination container
hr = _BrowseForDestination(lpszDestinationPath);
if (FAILED(hr) || (hr == S_FALSE))
{
return hr;
}
}
else
{
break;
}
}
else
{
bContinue = TRUE;
}
} while (!bContinue);
if (bContinue)
{
hr = _MoveSingleSel(szNewPath);
if (SUCCEEDED(hr))
{
GetComponentData()->InvalidateSavedQueriesContainingObjects(szMovedPathList);
}
return hr;
}
return S_FALSE;
}
hr = _MoveMultipleSel();
return hr;
}
BOOL CMoveHandlerBase::_ReportFailure(BOOL bLast, HRESULT hr, LPCWSTR lpszName)
{
TRACE(_T("Object Move Failed with hr: %lx\n"), hr);
PVOID apv[1] = {(LPWSTR)lpszName};
if (bLast)
{
// single selection or last one in multi selection
ReportErrorEx(GetParentHwnd(),IDS_12_FAILED_TO_MOVE_OBJECT,hr,
MB_OK | MB_ICONERROR, apv, 1);
return FALSE; // do not continue
}
return (ReportErrorEx(GetParentHwnd(),IDS_12_MULTI_FAILED_TO_MOVE_OBJECT,hr,
MB_YESNO, apv, 1) == IDYES);
}
HRESULT CMoveHandlerBase::_MoveSingleSel(PCWSTR pszNewPath)
{
if (!_BeginTransactionAndConfirmOperation())
return S_FALSE;
// JonN 1/28/02 507549 move connection object
CString szClass;
GetClassOfMovedItem( szClass );
CString szPath;
GetItemPath( 0, szPath );
HRESULT hr2 = _CheckMovedObject(szClass, szPath);
if (S_FALSE == hr2)
{
ReportMessageEx( GetParentHwnd(), IDS_MOVE_CONNECTION_TO_SELF );
return S_FALSE;
}
CComPtr<IDispatch> spDSTargetIDispatch;
HRESULT hr = m_spDSDestination->MoveHere(CComBSTR(pszNewPath),
NULL,
&spDSTargetIDispatch);
if (FAILED(hr))
{
CString szName;
GetName(0, szName);
_ReportFailure(TRUE, hr, szName);
}
else
{
// all went fine, notify extensions
GetTransaction()->Notify(0);
// give a chance to update UI (e.g. cookies)
CComPtr<IADs> spIADsTarget;
hr = spDSTargetIDispatch->QueryInterface (IID_IADs,
(void **)&spIADsTarget);
hr = OnItemMoved(0, spIADsTarget);
}
GetTransaction()->End();
return hr;
}
HRESULT CMoveHandlerBase::_MoveMultipleSel()
{
CThemeContextActivator activator;
if (!_BeginTransactionAndConfirmOperation())
return S_FALSE;
CMultipleMoveProgressDialog dlg(GetParentHwnd(), GetComponentData(), this);
dlg.DoModal();
return S_OK;
}
HRESULT CMoveHandlerBase::_OnMoveStep(IN UINT i,
OUT BOOL* pbCanContinue,
OUT CString& strrefPath,
OUT CString& strrefClass)
{
ASSERT(m_spDSDestination != NULL);
if (pbCanContinue == NULL)
{
return E_POINTER;
}
UINT nCount = GetItemCount();
//
// Initialize out parameters
//
GetItemPath(i, strrefPath);
strrefClass = GetItemClass(i);
*pbCanContinue = TRUE;
if (strrefPath == m_szDestPath)
{
return S_OK;
}
// try to execute the move
CString szNewPath;
CComPtr<IDispatch> spDSTargetIDispatch;
GetNewPath(i, szNewPath);
HRESULT hr = m_spDSDestination->MoveHere(CComBSTR(szNewPath),
NULL,
&spDSTargetIDispatch);
if (FAILED(hr))
{
CString szName;
GetName(i, szName);
if (nCount == 1)
{
*pbCanContinue = _ReportFailure((i == nCount-1), hr, szName);
}
}
else
{
// all went fine, notify extensions
GetTransaction()->Notify(i);
// give a chance to update UI (e.g. cookies)
CComPtr<IADs> spIADsTarget;
hr = spDSTargetIDispatch->QueryInterface (IID_IADs,
(void **)&spIADsTarget);
hr = OnItemMoved(i, spIADsTarget);
}
return hr;
}
// JonN 1/28/02 507549 move connection object
HRESULT CMoveHandlerBase::_CheckMovedObject(LPCWSTR pwszClass, LPCWSTR pwszPath)
{
if (NULL == pwszClass || NULL == pwszPath)
{
ASSERT(FALSE);
return S_OK;
}
if (_wcsicmp(pwszClass, L"nTDSConnection"))
return S_OK; // not a connection
// retrieve path to moved object
CPathCracker pathCracker;
CComBSTR sbstrDestPath = GetDestPath();
HRESULT hr = pathCracker.Set( sbstrDestPath, ADS_SETTYPE_FULL );
ASSERT( SUCCEEDED(hr) );
if ( !SUCCEEDED(hr) ) return S_OK;
hr = pathCracker.Set( (CComBSTR)pwszPath, ADS_SETTYPE_DN );
ASSERT( SUCCEEDED(hr) );
if ( !SUCCEEDED(hr) ) return S_OK;
CComBSTR sbstrADsPath;
hr = pathCracker.Retrieve( ADS_FORMAT_X500, &sbstrADsPath );
ASSERT( SUCCEEDED(hr) );
if ( !SUCCEEDED(hr) ) return S_OK;
// retrieve the fromServer attribute of the connection to be moved
CComPtr<IADs> spConnection;
hr = DSAdminOpenObject(sbstrADsPath,
IID_IADs,
(void **)&spConnection,
FALSE /*bServer*/);
if (FAILED(hr))
return S_OK; // could not read fromServer attribute
CComVariant svar;
hr = spConnection->Get((CComBSTR)L"fromServer", &svar);
if (FAILED(hr) || (VT_BSTR != svar.vt) || (NULL == svar.bstrVal))
return S_OK;
hr = pathCracker.Set( sbstrDestPath, ADS_SETTYPE_FULL );
ASSERT( SUCCEEDED(hr) );
if ( !SUCCEEDED(hr) ) return S_OK;
CComBSTR sbstrDestContainer;
hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &sbstrDestContainer );
ASSERT( SUCCEEDED(hr) );
if ( !SUCCEEDED(hr) ) return S_OK;
if ( !_wcsicmp(sbstrDestContainer, svar.bstrVal) )
return S_FALSE; // same path
return S_OK;
}
void BuildBrowseQueryString(LPCWSTR lpszSchemaNamingContext, BOOL bAdvancedView,
CString& szQueryString)
{
// allowed list of container classes
static LPCWSTR lpszAllowedContainers[] =
{
L"Organizational-Unit",
L"Builtin-Domain",
L"Lost-And-Found",
L"container",
NULL // end of table
};
CString sz = L"(|";
for (int k=0; lpszAllowedContainers[k] != NULL; k++)
{
sz += L"(ObjectCategory=CN=";
sz += lpszAllowedContainers[k];
sz += L",";
sz += lpszSchemaNamingContext;
sz += L")";
}
sz += L")";
if( bAdvancedView )
{
szQueryString = sz;
}
else
{
szQueryString.Format(L"(&%s(!showInAdvancedViewOnly=TRUE))", (LPCWSTR)sz);
}
}
int BrowseCallback(HWND, UINT uMsg, LPARAM lParam, LPARAM /*lpData*/)
{
switch (uMsg)
{
case DSBM_HELP:
{
TRACE(L"Browse Callback: msg is DSBM_HELP.\n");
LPHELPINFO pHelp = (LPHELPINFO) lParam;
TRACE(_T("CtrlId = %d, ContextId = 0x%x\n"),
pHelp->iCtrlId, pHelp->dwContextId);
if (pHelp->iCtrlId != DSBID_CONTAINERLIST) {
return 0; // not handled
}
::WinHelp((HWND)pHelp->hItemHandle,
DSADMIN_CONTEXT_HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_BROWSE_CONTAINER);
}
break;
} // switch
return 1; // handled
}
HRESULT CMoveHandlerBase::_BrowseForDestination(LPCWSTR lpszDestinationPath)
{
CThemeContextActivator activator;
m_spDSDestination = NULL;
m_szDestPath.Empty();
m_szDestClass.Empty();
// check if we have to expand computers in the Browse for container UI
CDSComponentData* pCD = GetComponentData();
BOOL bExpandComputers = FALSE;
if (pCD != NULL)
{
bExpandComputers = pCD->ExpandComputers();
}
// determine if we have to show the Browse for container dialog
CString strTargetContainer;
if (lpszDestinationPath != NULL)
{
// we have the target container already, no need to
// bring up UI
strTargetContainer = lpszDestinationPath;
}
else
{
// no container, need Browse dialog
CString strClassOfMovedItem;
GetClassOfMovedItem(strClassOfMovedItem);
if (0 == strClassOfMovedItem.CompareNoCase(L"server"))
{
HICON hIcon = NULL;
if (pCD != NULL)
{
MyBasePathsInfo* pBasePathsInfo = pCD->GetBasePathsInfo();
ASSERT(pBasePathsInfo != NULL);
hIcon = pBasePathsInfo->GetIcon(const_cast<LPTSTR>(gsz_site),
DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON | DSGIF_DEFAULTISCONTAINER,
16, 16);
}
CMoveServerDialog dlg( m_lpszBrowseRootPath, hIcon, CWnd::FromHandle(GetParentHwnd()) );
INT_PTR result = dlg.DoModal();
if (IDCANCEL == result)
return S_FALSE;
strTargetContainer = dlg.m_strTargetContainer;
}
else
{
PWSTR pszPath = new WCHAR[INTERNET_MAX_URL_LENGTH * 4];
if (!pszPath)
{
return E_OUTOFMEMORY;
}
pszPath[0] = TEXT('\0');
CString strTitle;
strTitle.LoadString (IDS_MOVE_TITLE);
DSBROWSEINFO dsbi;
::ZeroMemory( &dsbi, sizeof(dsbi) );
CString str;
str.LoadString(IDS_MOVE_TARGET);
dsbi.hwndOwner = GetParentHwnd();
// CODEWORK: Get DsBrowseForContainer to take const strings
dsbi.cbStruct = sizeof (DSBROWSEINFO);
dsbi.pszCaption = (LPWSTR)((LPCWSTR)strTitle); // this is actually the caption
dsbi.pszTitle = (LPWSTR)((LPCWSTR)str);
dsbi.pszRoot = (LPWSTR)m_lpszBrowseRootPath;
dsbi.pszPath = pszPath;
dsbi.cchPath = INTERNET_MAX_URL_LENGTH * 4;
dsbi.dwFlags = DSBI_RETURN_FORMAT |
DSBI_EXPANDONOPEN;
if( pCD && pCD->IsAdvancedView() )
{
dsbi.dwFlags |= DSBI_INCLUDEHIDDEN;
}
if (bExpandComputers)
{
dsbi.dwFlags |= DSBI_IGNORETREATASLEAF;
}
dsbi.pfnCallback = BrowseCallback;
dsbi.lParam = (LPARAM)pCD;
dsbi.dwReturnFormat = ADS_FORMAT_X500;
DWORD result = DsBrowseForContainer( &dsbi ); // returns -1, 0, IDOK or IDCANCEL
if (result != IDOK)
{
if (pszPath)
{
delete[] pszPath;
pszPath = 0;
}
return S_FALSE; // canceled by user
}
strTargetContainer = dsbi.pszPath;
if (pszPath)
{
delete[] pszPath;
pszPath = 0;
}
} // class is not server
} // have target container
if ( strTargetContainer.IsEmpty() ) // ADSI doesn't like this
{
ASSERT(FALSE);
return S_FALSE;
}
// try to open the target container
CComPtr<IADsContainer> spDSDestination;
HRESULT hr = DSAdminOpenObject(strTargetContainer,
IID_IADsContainer,
(void **)&spDSDestination,
FALSE /*bServer*/);
if (FAILED(hr))
{
CPathCracker pathCracker;
pathCracker.Set(CComBSTR(strTargetContainer),
ADS_SETTYPE_FULL);
pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
CComBSTR DestName;
pathCracker.GetElement( 0, &DestName );
PVOID apv[1] = {(BSTR)DestName};
ReportErrorEx(GetParentHwnd(),IDS_12_CONTAINER_NOT_FOUND,hr,
MB_OK | MB_ICONERROR, apv, 1);
return hr;
}
// need the class of the destination container
CComPtr<IADs> spIADs;
hr = spDSDestination->QueryInterface(IID_IADs, (void**)&spIADs);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
CComBSTR bstrClass;
hr = spIADs->get_Class(&bstrClass);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
// all went well, copy the output parameters
m_spDSDestination = spDSDestination;
m_szDestPath = strTargetContainer;
m_szDestClass = bstrClass;
m_bDestContainer = TRUE; // we do a move, it must be one
return hr;
}
BOOL CMoveHandlerBase::_BeginTransactionAndConfirmOperation()
{
CThemeContextActivator activator;
// start the transaction
HRESULT hr = BeginTransaction();
ASSERT(SUCCEEDED(hr));
// if needed, confirm
if (GetTransaction()->NeedNotifyCount() > 0)
{
CString szMessage;
CString szAssocData;
UINT nCount = GetItemCount();
if (nCount == 1)
{
szMessage.LoadString(IDS_CONFIRM_MOVE);
szAssocData.LoadString(IDS_EXTENS_SINGLE_MOVE);
}
else
{
CString szMessageFormat;
szMessageFormat.LoadString(IDS_CONFIRM_MULTIPLE_MOVE);
szMessage.Format(szMessageFormat, nCount);
szAssocData.LoadString(IDS_EXTENS_MULTIPLE_MOVE);
}
CConfirmOperationDialog dlg(GetParentHwnd(), GetTransaction());
dlg.SetStrings(szMessage, szAssocData);
if (IDNO == dlg.DoModal())
{
GetTransaction()->End();
return FALSE;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////
// IsHomogenousDSSelection
//
// pDataObject must support the DSAdmin internal clipboard format
//
// if the return value is true, szClassName will be the name of
// the class of the homogenous selection
//
BOOL IsHomogenousDSSelection(LPDATAOBJECT pDataObject, CString& szClassName)
{
BOOL bHomogenous = TRUE;
szClassName = L"";
if (pDataObject == NULL)
{
ASSERT(FALSE);
return FALSE;
}
CInternalFormatCracker ifc;
HRESULT hr = ifc.Extract(pDataObject);
if (FAILED(hr))
{
ASSERT(FALSE);
return FALSE;
}
CUINode* pUINode = ifc.GetCookie();
ASSERT(pUINode != NULL);
CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(pUINode);
if (pDSUINode == NULL)
{
ASSERT(FALSE);
return FALSE;
}
CDSCookie* pCookie = GetDSCookieFromUINode(pDSUINode);
if (pCookie == NULL)
{
ASSERT(FALSE);
return FALSE;
}
szClassName = pCookie->GetClass();
ASSERT(!szClassName.IsEmpty());
for (UINT idx = 1; idx < ifc.GetCookieCount(); idx++)
{
CUINode* pSelectedUINode = ifc.GetCookie(idx);
ASSERT(pSelectedUINode);
CDSUINode* pSelectedDSUINode = dynamic_cast<CDSUINode*>(pSelectedUINode);
if (!pSelectedDSUINode)
{
bHomogenous = FALSE;
break;
}
CDSCookie* pSelectedCookie = GetDSCookieFromUINode(pSelectedDSUINode);
if (!pSelectedCookie)
{
ASSERT(FALSE);
bHomogenous = FALSE;
break;
}
if (wcscmp(szClassName, pSelectedCookie->GetClass()) != 0)
{
bHomogenous = FALSE;
break;
}
}
if (!bHomogenous)
{
szClassName = L"";
}
return bHomogenous;
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// Temporary Tab Collector stuff
//
//+----------------------------------------------------------------------------
//
// Function: AddPageProc
//
// Synopsis: The IShellPropSheetExt->AddPages callback.
//
//-----------------------------------------------------------------------------
BOOL CALLBACK AddPageProc(HPROPSHEETPAGE hPage, LPARAM pCall)
{
TRACE(_T("xx.%03x> AddPageProc()\n"), GetCurrentThreadId());
HRESULT hr;
hr = ((LPPROPERTYSHEETCALLBACK)pCall)->AddPage(hPage);
return hr == S_OK;
}
HRESULT GetDisplaySpecifierProperty(PCWSTR pszClassName,
PCWSTR pszDisplayProperty,
MyBasePathsInfo* pBasePathsInfo,
CStringList& strListRef,
bool bEnglishOnly)
{
HRESULT hr = S_OK;
//
// Validate parameters
// Note : pszClassName can be NULL and will retrieve the default-Display values
//
if (pszDisplayProperty == NULL ||
pBasePathsInfo == NULL)
{
ASSERT(FALSE);
return E_POINTER;
}
CComPtr<IADs> spIADs;
if (!bEnglishOnly)
{
hr = pBasePathsInfo->GetDisplaySpecifier(pszClassName, IID_IADs, (PVOID*)&spIADs);
}
else
{
//
// Build the path to the English display specifier container
//
CString szConfigDN = pBasePathsInfo->GetConfigNamingContext();
CString szEnglishDisplaySpecifierDN = L"CN=409,CN=DisplaySpecifiers," + szConfigDN;
CString szDisplayObjectDN = L"CN=" + CString(pszClassName) + L"-Display," + szEnglishDisplaySpecifierDN;
CString szDisplayObjectPath;
pBasePathsInfo->ComposeADsIPath(szDisplayObjectPath, szDisplayObjectDN);
//
// Open the object and get the property
//
hr = DSAdminOpenObject(szDisplayObjectPath,
IID_IADs,
(void**)&spIADs,
true);
}
if (SUCCEEDED(hr) && !!spIADs)
{
CComVariant var;
hr = spIADs->Get(CComBSTR(pszDisplayProperty), &var);
if (SUCCEEDED(hr))
{
hr = HrVariantToStringList(var, strListRef);
}
}
return hr;
}
HRESULT TabCollect_GetDisplayGUIDs(LPCWSTR lpszClassName,
LPCWSTR lpszDisplayProperty,
MyBasePathsInfo* pBasePathsInfo,
UINT* pnCount,
GUID** ppGuids)
{
HRESULT hr = S_OK;
//
// This should bind to the display specifiers, get the specified property and
// sort the guids by ordered pairs and return the guids
//
if (pBasePathsInfo == NULL)
{
*pnCount = 0;
*ppGuids = NULL;
return E_FAIL;
}
CStringList szPropertyList;
hr = GetDisplaySpecifierProperty(lpszClassName, lpszDisplayProperty, pBasePathsInfo, szPropertyList);
if (FAILED(hr))
{
*pnCount = 0;
*ppGuids = NULL;
return hr;
}
if (szPropertyList.GetCount() < 1)
{
//
// Couldn't find anything for the class, try to find something in the default-Display
//
hr = GetDisplaySpecifierProperty(L"default", lpszDisplayProperty, pBasePathsInfo, szPropertyList);
if (FAILED(hr))
{
//
// If still nothing is found revert to the English display specifiers
//
hr = GetDisplaySpecifierProperty(lpszClassName, lpszDisplayProperty, pBasePathsInfo, szPropertyList, true);
if (FAILED(hr))
{
*pnCount = 0;
*ppGuids = NULL;
return hr;
}
if (szPropertyList.GetCount() < 1)
{
//
// Now try the English default
//
hr = GetDisplaySpecifierProperty(L"default", lpszDisplayProperty, pBasePathsInfo, szPropertyList, true);
if (FAILED(hr))
{
*pnCount = 0;
*ppGuids = NULL;
return hr;
}
}
}
}
*pnCount = static_cast<UINT>(szPropertyList.GetCount());
*ppGuids = new GUID[*pnCount];
if (*ppGuids == NULL)
{
*pnCount = 0;
*ppGuids = NULL;
return hr;
}
int* pnIndex = new int[*pnCount];
if (pnIndex == NULL)
{
*pnCount = 0;
*ppGuids = NULL;
return hr;
}
CString szIndex;
CString szGUID;
UINT itr = 0;
POSITION pos = szPropertyList.GetHeadPosition();
while (pos != NULL)
{
CString szItem = szPropertyList.GetNext(pos);
int nComma = szItem.Find(L",");
if (nComma == -1)
continue;
szIndex = szItem.Left(nComma);
int nIndex = _wtoi((LPCWSTR)szIndex);
if (nIndex <= 0)
continue; // allow from 1 up
// strip leading and traling blanks
szGUID = szItem.Mid(nComma+1);
szGUID.TrimLeft();
szGUID.TrimRight();
GUID guid;
hr = ::CLSIDFromString((LPWSTR)(LPCWSTR)szGUID, &guid);
if (SUCCEEDED(hr))
{
(*ppGuids)[itr] = guid;
pnIndex[itr] = nIndex;
itr++;
}
}
//
// Must sort the page list
//
while (TRUE)
{
BOOL bSwapped = FALSE;
for (UINT k=1; k < *pnCount; k++)
{
if (pnIndex[k] < pnIndex[k-1])
{
// swap
int nTemp = pnIndex[k];
pnIndex[k] = pnIndex[k-1];
pnIndex[k-1] = nTemp;
GUID temp = *ppGuids[k];
*ppGuids[k] = *ppGuids[k-1];
*ppGuids[k-1] = temp;
bSwapped = TRUE;
}
}
if (!bSwapped)
{
break;
}
}
//
// Cleanup the index array
//
if (pnIndex != NULL)
{
delete[] pnIndex;
}
return hr;
}
//**********************************************************************
// Test code to improve the search process on cookies
BOOL _SearchTreeForCookie(IN CUINode* pContainerNode, // current container where to start the search
IN CPathCracker* pPathCracker, // path cracker with the tokenized search path
IN long nCurrentToken, // current token in the path cracker
IN BOOL bSearchSubcontainers, // flag to search subcontainers
OUT CUINode** ppUINode // returned node
)
{
ASSERT(pContainerNode != NULL);
ASSERT(pContainerNode->IsContainer());
long nPathElements = 0;
pPathCracker->GetNumElements(&nPathElements);
if (nCurrentToken >= nPathElements)
{
// ran out of tokens to compare
return FALSE;
}
CComBSTR bstrCurrentToken;
pPathCracker->GetElement(nCurrentToken, &bstrCurrentToken);
// decide which list to look into
CUINodeList* pNodeList = NULL;
if (bSearchSubcontainers)
pNodeList = pContainerNode->GetFolderInfo()->GetContainerList();
else
pNodeList = pContainerNode->GetFolderInfo()->GetLeafList();
CPathCracker pathCrackerCurr;
for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; )
{
CUINode* pCurrentNode = pNodeList->GetNext(pos);
if (!IS_CLASS(pCurrentNode, DS_UI_NODE))
{
// not a node with a cookie, just skip
continue;
}
// get the cookie from the node
CDSCookie* pCurrentCookie = GetDSCookieFromUINode(pCurrentNode);
// build the naming token (leaf element of the path), e.g. "CN=foo"
CComBSTR bstrCurrentNamingToken;
pathCrackerCurr.Set((BSTR)pCurrentCookie->GetPath(), ADS_SETTYPE_DN);
pathCrackerCurr.GetElement(0, &bstrCurrentNamingToken);
// compare the current naming token with the current search token
TRACE(L"comparing bstrCurrentToken = %s, bstrCurrentNamingToken = %s\n",
bstrCurrentToken, bstrCurrentNamingToken);
if (_wcsicmp(bstrCurrentToken, bstrCurrentNamingToken) == 0)
{
// the token matches, need to see if we are at the end of the
// list of tokens
if (nCurrentToken == 0)
{
*ppUINode = pCurrentNode;
return TRUE; // got it!!!
}
else
{
// we match, but we have to go one level deeper
BOOL bFound = FALSE;
if (nCurrentToken == 1)
{
// try on leaf nodes, we are at the last level
bFound = _SearchTreeForCookie(pCurrentNode, pPathCracker, nCurrentToken-1, FALSE, ppUINode);
}
if (bFound)
return TRUE;
// try on subcontainers
return _SearchTreeForCookie(pCurrentNode, pPathCracker, nCurrentToken-1, TRUE, ppUINode);
}
}
// if no match, we keep scanning at this level
} // for
return FALSE; // not found
}
BOOL FindCookieInSubtree(IN CUINode* pContainerNode,
IN LPCWSTR lpszCookieDN,
IN SnapinType snapinType,
OUT CUINode** ppUINode)
{
*ppUINode = NULL;
if (!pContainerNode->IsContainer())
{
// not the right type of node
return FALSE;
}
LPCWSTR lpszStartingContainerPath = NULL;
long nAdjustLevel = 0;
if (IS_CLASS(pContainerNode, DS_UI_NODE) )
{
lpszStartingContainerPath = dynamic_cast<CDSUINode*>(pContainerNode)->GetCookie()->GetPath();
nAdjustLevel = 1;
}
else if (IS_CLASS(pContainerNode, ROOT_UI_NODE) )
{
lpszStartingContainerPath = dynamic_cast<CRootNode*>(pContainerNode)->GetPath();
if (snapinType == SNAPINTYPE_SITE)
{
nAdjustLevel = 1;
}
}
if (lpszStartingContainerPath == NULL)
{
// bad node type
return FALSE;
}
// instantiate a path cracker for the DN we are in search of
CPathCracker pathCrackerDN;
HRESULT hr = pathCrackerDN.Set((BSTR)lpszCookieDN, ADS_SETTYPE_DN);
long nPathElementsDN = 0;
hr = pathCrackerDN.GetNumElements(&nPathElementsDN);
if ( FAILED(hr) || (nPathElementsDN <= 0) )
{
// bad path
ASSERT(FALSE);
return FALSE;
}
// instantiate a path cracker for the container node
CPathCracker pathCrackerStartingContainer;
pathCrackerStartingContainer.Set((BSTR)lpszStartingContainerPath, ADS_SETTYPE_DN);
long nPathElementsStartingContainer = 0;
pathCrackerStartingContainer.GetNumElements(&nPathElementsStartingContainer);
if ( FAILED(hr) || (nPathElementsStartingContainer <= 0) )
{
// bad path
ASSERT(FALSE);
return FALSE;
}
// compute the level where we start the search from
long nStartToken = nPathElementsDN - nPathElementsStartingContainer - nAdjustLevel;
if ( nStartToken < 0)
{
return FALSE;
}
if (( nStartToken == 0) && (nAdjustLevel == 1) && snapinType != SNAPINTYPE_SITE)
{
return FALSE;
}
return _SearchTreeForCookie(pContainerNode, &pathCrackerDN, nStartToken /*current token*/, TRUE, ppUINode);
}
//**********************************************************************
///////////////////////////////////////////////////////////////////////////
// CMultiselectMoveDataObject
// helper function for CDSEvent::_Paste()
// to create a data object containing the successfully pasted items
HRESULT CMultiselectMoveDataObject::BuildPastedDataObject(
IN CObjectNamesFormatCracker* pObjectNamesFormatPaste,
IN CMultiselectMoveHandler* pMoveHandler,
IN CDSComponentData* pCD,
OUT IDataObject** ppSuccesfullyPastedDataObject)
{
// verify input parameters
if (ppSuccesfullyPastedDataObject == NULL)
{
return E_INVALIDARG;
}
*ppSuccesfullyPastedDataObject = NULL;
if ((pObjectNamesFormatPaste == NULL) || (pMoveHandler == NULL) )
{
return E_INVALIDARG;
}
//
// need to build a data object and hang on to it
//
CComObject<CMultiselectMoveDataObject>* pObject;
CComObject<CMultiselectMoveDataObject>::CreateInstance(&pObject);
if (pObject == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pObject->FinalConstruct();
if (FAILED(hr))
{
delete pObject;
return hr;
}
hr = pObject->Init(pObjectNamesFormatPaste, pMoveHandler, pCD);
if (FAILED(hr))
{
delete pObject;
return hr;
}
hr = pObject->QueryInterface(IID_IDataObject,
reinterpret_cast<void**>(ppSuccesfullyPastedDataObject));
if (FAILED(hr))
{
//
// delete object by calling Release()
//
(*ppSuccesfullyPastedDataObject)->Release();
(*ppSuccesfullyPastedDataObject) = NULL;
}
return hr;
}
CLIPFORMAT CMultiselectMoveDataObject::m_cfDsObjectNames =
(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
STDMETHODIMP CMultiselectMoveDataObject::GetData(FORMATETC * pFormatEtc, STGMEDIUM * pMedium)
{
if ((pFormatEtc == NULL) || (pMedium == NULL))
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pMedium, sizeof(STGMEDIUM)))
{
return E_INVALIDARG;
}
if (!(pFormatEtc->tymed & TYMED_HGLOBAL))
{
return DV_E_TYMED;
}
// we support only one clipboard format
pMedium->tymed = TYMED_HGLOBAL;
pMedium->pUnkForRelease = NULL;
if (pFormatEtc->cfFormat != m_cfDsObjectNames)
{
return DV_E_FORMATETC;
}
//NTRAID#NTBUG9-571999-2002/03/10-jmessec If pMedium->hGlobal already pointed to allocated memory, here is a memory leak
// make a deep copy of the cached data
pMedium->hGlobal = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
m_nDSObjCachedBytes);
if (pMedium->hGlobal == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(pMedium->hGlobal, m_pDSObjCached, m_nDSObjCachedBytes);
pMedium->tymed = TYMED_HGLOBAL;
pMedium->pUnkForRelease = NULL;
return S_OK;
}
HRESULT CMultiselectMoveDataObject::Init(
IN CObjectNamesFormatCracker* pObjectNamesFormatPaste,
IN CMultiselectMoveHandler* pMoveHandler,
IN CDSComponentData* pCD)
{
_Clear();
// figure out how much storage we need
//
// this loop is to calc how much storage we need.
//
UINT nPasteCount = pObjectNamesFormatPaste->GetCount();
UINT nSuccessfulPasteCount = 0;
size_t cbStorage = 0;
for (UINT i=0; i<nPasteCount; i++)
{
if (pMoveHandler->WasItemMoved(i))
{
nSuccessfulPasteCount++;
cbStorage += (wcslen(pObjectNamesFormatPaste->GetClass(i)) + 1 +
wcslen(pObjectNamesFormatPaste->GetName(i)) + 1) * sizeof(WCHAR);
}
}
if (nSuccessfulPasteCount == 0)
{
// no items were successfully pasted
return E_INVALIDARG;
}
// NOTICE: contains already a DSOBJECT embedded struct, so we subtract 1
DWORD cbStruct = sizeof(DSOBJECTNAMES) +
((nSuccessfulPasteCount - 1) * sizeof(DSOBJECT));
//
// Allocate the needed storage
//
m_pDSObjCached = (LPDSOBJECTNAMES)malloc(cbStruct + cbStorage);
if (m_pDSObjCached == NULL)
{
return E_OUTOFMEMORY;
}
m_nDSObjCachedBytes = static_cast<ULONG>(cbStruct + cbStorage);
switch (pCD->QuerySnapinType())
{
case SNAPINTYPE_DS:
m_pDSObjCached->clsidNamespace = CLSID_DSSnapin;
break;
case SNAPINTYPE_SITE:
m_pDSObjCached->clsidNamespace = CLSID_SiteSnapin;
break;
default:
m_pDSObjCached->clsidNamespace = CLSID_NULL;
}
m_pDSObjCached->cItems = nSuccessfulPasteCount;
DWORD NextOffset = cbStruct;
UINT index = 0;
for (i=0; i<nPasteCount; i++)
{
if (pMoveHandler->WasItemMoved(i))
{
//
// Set the data from the node and node data
//
size_t nNameLen = wcslen(pObjectNamesFormatPaste->GetName(i));
size_t nClassLen = wcslen(pObjectNamesFormatPaste->GetClass(i));
//NTRAID#NTBUG9-567482-2002/03/10-jmessec ASSERT not handled with code
ASSERT((nNameLen > 0) && (nClassLen > 0));
m_pDSObjCached->aObjects[index].dwFlags = pObjectNamesFormatPaste->IsContainer(i) ? DSOBJECT_ISCONTAINER : 0;
m_pDSObjCached->aObjects[index].dwProviderFlags = (pCD->IsAdvancedView()) ?
DSPROVIDER_ADVANCED : 0;
m_pDSObjCached->aObjects[index].offsetName = NextOffset;
m_pDSObjCached->aObjects[index].offsetClass = static_cast<ULONG>(NextOffset +
(nNameLen + 1) * sizeof(WCHAR));
_tcscpy((LPTSTR)((BYTE *)m_pDSObjCached + NextOffset), pObjectNamesFormatPaste->GetName(i));
NextOffset += static_cast<ULONG>((nNameLen + 1) * sizeof(WCHAR));
_tcscpy((LPTSTR)((BYTE *)m_pDSObjCached + NextOffset), pObjectNamesFormatPaste->GetClass(i));
NextOffset += static_cast<ULONG>((nClassLen + 1) * sizeof(WCHAR));
index++;
} // if
} // for
return S_OK;
}
void EscapeFilterElement(PCWSTR pszElement, CString& refszEscapedElement)
{
// do LDAP escaping (as per RFC 2254)
for (const WCHAR* pChar = pszElement; (*pChar) != NULL; pChar++)
{
switch (*pChar)
{
case L'*':
refszEscapedElement += L"\\2a";
break;
case L'(':
refszEscapedElement += L"\\28";
break;
case L')':
refszEscapedElement += L"\\29";
break;
case L'\\':
refszEscapedElement += L"\\5c";
break;
default:
refszEscapedElement += (*pChar);
} // switch
} // for
}