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.
 
 
 
 
 
 

747 lines
23 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: editorui.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#include <SnapBase.h>
#include "resource.h"
#include "attredit.h"
#include "adsiedit.h"
#include "editor.h"
#include "editorui.h"
#include "snapdata.h"
#include "common.h"
#include <aclpage.h>
#include <dssec.h> // For AclEditor flags
#include "connection.h"
#ifdef DEBUG_ALLOCATOR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
////////////////////////////////////////////////////////////////////////////
// this is used to fill in the attributes for RootDSE
//
typedef struct tagRootDSEAttr
{
LPCWSTR lpszAttr;
LPCWSTR lpszSyntax;
BOOL bMulti;
} SYNTAXMAP;
SYNTAXMAP g_ldapRootDSESyntax[] =
{
_T("currentTime"), _T("2.5.5.11"), FALSE,
_T("subschemaSubentry"), _T("2.5.5.1"), FALSE,
_T("serverName"), _T("2.5.5.1"), FALSE,
_T("namingContexts"), _T("2.5.5.1"), TRUE,
_T("defaultNamingContext"), _T("2.5.5.1"), FALSE,
_T("schemaNamingContext"), _T("2.5.5.1"), FALSE,
_T("configurationNamingContext"), _T("2.5.5.1"), FALSE,
_T("rootDomainNamingContext"), _T("2.5.5.1"), FALSE,
_T("supportedControl"), _T("2.5.5.2"), TRUE,
_T("supportedLDAPVersion"), _T("2.5.5.9"), TRUE,
_T("supportedLDAPPolicies"), _T("2.5.5.4"), TRUE,
_T("supportedSASLMechanisms"), _T("2.5.5.4"), TRUE,
_T("dsServiceName"), _T("2.5.5.1"), FALSE,
_T("dnsHostName"), _T("2.5.5.4"), FALSE,
_T("supportedCapabilities"), _T("2.5.5.2"), TRUE,
_T("ldapServiceName"), _T("2.5.5.4"), FALSE,
_T("highestCommittedUsn"), _T("2.5.5.4"), FALSE, // this should be an integer but after investigation I found it was a string
_T("domainControllerFunctionality"),_T("2.5.5.9"), FALSE,
_T("domainFunctionality"), _T("2.5.5.9"), FALSE,
_T("forestFunctionality"), _T("2.5.5.9"), FALSE,
_T("isGlobalCatalogReady"), _T("2.5.5.8"), FALSE,
_T("isSynchronized"), _T("2.5.5.8"), FALSE,
NULL, 0,
};
extern LPCWSTR g_lpszGC;
/////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CADSIEditPropertyPage, CPropertyPageBase)
//{{AFX_MSG_MAP(CADsObjectDialog)
ON_CBN_SELCHANGE(IDC_PROP_BOX, OnSelChangeAttrList)
ON_CBN_SELCHANGE(IDC_PROPTYPES_BOX, OnSelChangePropList)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CADSIEditPropertyPage::CADSIEditPropertyPage()
: CPropertyPageBase(IDD_PROPERTY_PAGE)
{
m_bExisting = TRUE;
}
CADSIEditPropertyPage::CADSIEditPropertyPage(CAttrList* pAttrs)
: CPropertyPageBase(IDD_PROPERTY_PAGE)
{
ASSERT(pAttrs != NULL);
m_pOldAttrList = pAttrs;
m_bExisting = FALSE;
CopyAttrList(pAttrs);
}
void CADSIEditPropertyPage::CopyAttrList(CAttrList* pAttrList)
{
m_AttrList.RemoveAll();
POSITION pos = pAttrList->GetHeadPosition();
while (pos != NULL)
{
m_AttrList.AddHead(pAttrList->GetNext(pos));
}
}
BOOL CADSIEditPropertyPage::OnInitDialog()
{
CPropertyPageBase::OnInitDialog();
// Get the dialog items
//
CEdit* pPathBox = (CEdit*)GetDlgItem(IDC_PATH_BOX);
CEdit* pClassBox = (CEdit*)GetDlgItem(IDC_CLASS_BOX);
CComboBox* pPropSelectBox = (CComboBox*)GetDlgItem(IDC_PROPTYPES_BOX);
CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
CStatic* pPathLabel = (CStatic*)GetDlgItem(IDC_PATH_LABEL);
CStatic* pClassLabel = (CStatic*)GetDlgItem(IDC_CLASS_LABEL);
CStatic* pFilterLabel = (CStatic*)GetDlgItem(IDC_FILTER_LABEL);
CStatic* pPropertyLabel = (CStatic*)GetDlgItem(IDC_PROPERTY_LABEL);
CStatic* pSyntaxLabel = (CStatic*)GetDlgItem(IDC_SYNTAX_LABEL);
CStatic* pEditLabel = (CStatic*)GetDlgItem(IDC_EDIT_LABEL);
CStatic* pValueLabel = (CStatic*)GetDlgItem(IDC_VALUE_LABEL);
CButton* pAttrGroup = (CButton*)GetDlgItem(IDC_ATTR_GROUP);
CStatic* pNoInfoLabel = (CStatic*)GetDlgItem(IDC_NO_INFO);
if (m_bExisting)
{
// This determines whether the node is complete with data or not. If not we won't enable
// the UI
//
BOOL bComplete = TRUE;
CADsObject* pADsObject = NULL;
CTreeNode* pTreeNode = GetHolder()->GetTreeNode();
CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(pTreeNode);
if (pContNode == NULL)
{
CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(pTreeNode);
ASSERT(pLeafNode != NULL);
pADsObject = pLeafNode->GetADsObject();
m_pConnectData = pADsObject->GetConnectionNode()->GetConnectionData();
bComplete = pADsObject->IsComplete();
}
else
{
pADsObject = pContNode->GetADsObject();
m_pConnectData = pADsObject->GetConnectionNode()->GetConnectionData();
bComplete = pADsObject->IsComplete();
}
// Initialize the attribute editor
//
m_attrEditor.Initialize(this, pTreeNode, m_sServer,
IDC_EDITVALUE_BOX, IDC_SYNTAX_BOX,
IDC_VALUE_EDITBOX, IDC_VALUE_LISTBOX,
IDC_ADD_BUTTON, IDC_REMOVE_BUTTON,
bComplete);
// Get the UI to reflect the data
//
if ( bComplete)
{
pPathBox->SetWindowText(m_sPath);
GetProperties();
pClassBox->SetWindowText(m_sClass);
CString sMand, sOpt, sBoth;
if (!sMand.LoadString(IDS_MANDATORY) ||
!sOpt.LoadString(IDS_OPTIONAL) ||
!sBoth.LoadString(IDS_BOTH))
{
ADSIEditMessageBox(IDS_MSG_FAIL_TO_LOAD, MB_OK);
}
if (m_pConnectData->IsRootDSE())
{
pPropSelectBox->AddString(sMand);
pPropSelectBox->SetCurSel(0);
}
else
{
pPropSelectBox->AddString(sMand);
pPropSelectBox->AddString(sOpt);
pPropSelectBox->AddString(sBoth);
pPropSelectBox->SetCurSel(1);
}
OnSelChangePropList();
pPropertyBox->SetCurSel(0);
}
else
{
pClassBox->ShowWindow(SW_HIDE);
pPropSelectBox->ShowWindow(SW_HIDE);
pPropertyBox->ShowWindow(SW_HIDE);
pPathLabel->ShowWindow(SW_HIDE);
pClassLabel->ShowWindow(SW_HIDE);
pFilterLabel->ShowWindow(SW_HIDE);
pPropertyLabel->ShowWindow(SW_HIDE);
pSyntaxLabel->ShowWindow(SW_HIDE);
pEditLabel->ShowWindow(SW_HIDE);
pValueLabel->ShowWindow(SW_HIDE);
pAttrGroup->ShowWindow(SW_HIDE);
pNoInfoLabel->ShowWindow(SW_SHOW);
}
}
else
{
// Initialize the attribute editor
//
m_attrEditor.Initialize(this, m_pConnectData, m_sServer,
IDC_EDITVALUE_BOX, IDC_SYNTAX_BOX,
IDC_VALUE_EDITBOX, IDC_VALUE_LISTBOX,
IDC_ADD_BUTTON, IDC_REMOVE_BUTTON,
TRUE, &m_AttrList);
pPathBox->SetWindowText(m_sPath);
GetProperties();
pClassBox->SetWindowText(m_sClass);
CString sMand, sOpt, sBoth;
if (!sMand.LoadString(IDS_MANDATORY) ||
!sOpt.LoadString(IDS_OPTIONAL) ||
!sBoth.LoadString(IDS_BOTH))
{
ADSIEditMessageBox(IDS_MSG_FAIL_TO_LOAD, MB_OK);
}
if (m_pConnectData->IsRootDSE())
{
pPropSelectBox->AddString(sMand);
pPropSelectBox->SetCurSel(0);
}
else
{
pPropSelectBox->AddString(sMand);
pPropSelectBox->AddString(sOpt);
pPropSelectBox->AddString(sBoth);
pPropSelectBox->SetCurSel(1);
}
OnSelChangePropList();
pPropertyBox->SetCurSel(0);
}
return TRUE;
}
BOOL CADSIEditPropertyPage::OnApply()
{
if( m_attrEditor.OnApply())
{
if (!m_bExisting)
{
m_pOldAttrList->RemoveAll();
while (!m_AttrList.IsEmpty())
{
m_pOldAttrList->AddTail(m_AttrList.RemoveTail());
}
}
}
else
{
return FALSE;
}
return TRUE;
}
void CADSIEditPropertyPage::OnCancel()
{
if (!m_bExisting)
{
while (!m_AttrList.IsEmpty())
{
CADSIAttr* pAttr = m_AttrList.RemoveTail();
ASSERT(pAttr != NULL);
CString szProp;
pAttr->GetProperty(szProp);
if (!m_pOldAttrList->HasProperty(szProp))
{
delete pAttr;
}
}
}
}
void CADSIEditPropertyPage::SetAttrList(CAttrList* pAttrList)
{
ASSERT(pAttrList != NULL);
m_pOldAttrList = pAttrList;
}
void CADSIEditPropertyPage::OnSelChangePropList()
{
// Filter the properties list
//
FillAttrList();
OnSelChangeAttrList();
}
void CADSIEditPropertyPage::OnSelChangeAttrList()
{
CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
int idx, iCount;
CString s;
HRESULT hr;
idx = pPropertyBox->GetCurSel();
// Make sure a property was selected
//
if ( idx == LB_ERR )
{
return;
}
pPropertyBox->GetLBText( idx, s );
// Have the attribute editor display the values for the new property
//
m_attrEditor.SetAttribute(s, m_sPath);
}
BOOL CADSIEditPropertyPage::GetProperties()
{
CString schema;
//Get the class object so that we can get the properties
//
if (!m_pConnectData->IsRootDSE()) // Not RootDSE
{
m_pConnectData->GetAbstractSchemaPath(schema);
schema += m_sClass;
// bind to object with authentication
//
CComPtr<IADsClass> pClass;
HRESULT hr, hCredResult;
hr = OpenObjectWithCredentials(
m_pConnectData,
m_pConnectData->GetCredentialObject()->UseCredentials(),
schema,
IID_IADsClass,
(LPVOID*) &pClass,
GetSafeHwnd(),
hCredResult
);
if ( FAILED(hr) )
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
}
return FALSE;
}
// Get the Mandatory Properties
//
VARIANT var;
VariantInit(&var);
hr = pClass->get_MandatoryProperties(&var);
if ( FAILED(hr) )
{
ADSIEditErrorMessage(hr);
return FALSE;
}
VariantToStringList( var, m_sMandatoryAttrList );
VariantClear(&var);
// Remove the nTSecurityDescriptor from the list because the aclEditor replaces it for ui purposes
//
m_sMandatoryAttrList.RemoveAt(m_sMandatoryAttrList.Find(_T("nTSecurityDescriptor")));
// Get the Optional Properties
//
VariantInit(&var);
hr = pClass->get_OptionalProperties(&var);
if ( FAILED(hr) )
{
ADSIEditErrorMessage(hr);
return FALSE;
}
VariantToStringList( var, m_sOptionalAttrList );
VariantClear(&var);
}
else // RootDSE
{
int idx=0;
// Add in the predefined attributes for the RootDSE
//
while( g_ldapRootDSESyntax[idx].lpszAttr )
{
m_sMandatoryAttrList.AddTail(g_ldapRootDSESyntax[idx].lpszAttr);
idx++;
}
}
return TRUE;
}
void CADSIEditPropertyPage::FillAttrList()
{
CComboBox* pPropSelectBox = (CComboBox*)GetDlgItem(IDC_PROPTYPES_BOX);
CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
POSITION pos;
CString s;
// Clean out the property box
//
int iCount = pPropertyBox->GetCount();
while (iCount > 0)
{
pPropertyBox->DeleteString(0);
iCount--;
}
// Get the filter to use
//
int idx = pPropSelectBox->GetCurSel();
if ( idx == LB_ERR )
{
return;
}
// Fill in the property box using the filter
//
if (idx == IDS_BOTH - IDS_MANDATORY)
{
AddPropertiesToBox(TRUE, TRUE);
}
else if (idx == IDS_MANDATORY - IDS_MANDATORY)
{
AddPropertiesToBox(TRUE, FALSE);
}
else
{
AddPropertiesToBox(FALSE, TRUE);
}
pPropertyBox->SetCurSel(0);
}
void CADSIEditPropertyPage::AddPropertiesToBox(BOOL bMand, BOOL bOpt)
{
CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
POSITION pos;
if (bMand)
{
// Add Mandatory Properties
//
pos = m_sMandatoryAttrList.GetHeadPosition();
while( pos != NULL )
{
CString s = m_sMandatoryAttrList.GetNext(pos);
if ( !s.IsEmpty())
{
pPropertyBox->AddString( s );
}
}
}
if (bOpt)
{
// Add Optional Properties
//
pos = m_sOptionalAttrList.GetHeadPosition();
while( pos != NULL )
{
CString s = m_sOptionalAttrList.GetNext(pos);
if ( !s.IsEmpty())
{
pPropertyBox->AddString( s );
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
CADSIEditPropertyPageHolder::CADSIEditPropertyPageHolder(CADSIEditContainerNode* pContainerNode,
CTreeNode* pThisNode, CComponentDataObject* pComponentData,
LPCWSTR lpszClass, LPCWSTR lpszServer, LPCWSTR lpszPath)
: CPropertyPageHolderBase(pContainerNode, pThisNode, pComponentData)
{
ASSERT(pComponentData != NULL);
ASSERT(pContainerNode != NULL);
m_pContainer = pContainerNode;
ASSERT(pContainerNode == GetContainerNode());
ASSERT(pThisNode != NULL);
m_pAclEditorPage = NULL;
m_bAutoDeletePages = FALSE; // we have the page as embedded member
m_sPath = lpszPath;
m_pADs = NULL;
//
// This gets the CConnectionData from the ConnectionNode by finding a valid treenode and using its
// CADsObject to get the ConnectionNode and then the CConnectionData
//
CADSIEditContainerNode* pNode = GetContainerNode();
CADSIEditConnectionNode* pConnectNode = pNode->GetADsObject()->GetConnectionNode();
CConnectionData* pConnectData = pConnectNode->GetConnectionData();
CCredentialObject* pCredObject = pConnectData->GetCredentialObject();
HRESULT hr, hCredResult;
hr = OpenObjectWithCredentials(
pConnectData,
pConnectData->GetCredentialObject()->UseCredentials(),
m_sPath,
IID_IADs,
(LPVOID*) &m_pADs,
NULL,
hCredResult
);
if (SUCCEEDED(hr))
{
//
// Create the advanced attribute editor
//
hr = ::CoCreateInstance(CLSID_DsAttributeEditor, NULL, CLSCTX_INPROC_SERVER,
IID_IDsAttributeEditor, (void**)&m_spIDsAttributeEditor);
if (SUCCEEDED(hr))
{
CString szLDAP;
pConnectData->GetLDAP(szLDAP);
CString szServer;
pConnectData->GetDomainServer(szServer);
CString szPort;
pConnectData->GetPort(szPort);
// NTRAID#NTBUG9-762158-2003/01/12-artm
// If targeting the GC the server name will be empty.
CString szProviderServer;
if (!szServer.IsEmpty())
{
if (!szPort.IsEmpty())
{
szProviderServer = szLDAP + szServer + _T(":") + szPort + _T("/");
}
else
{
szProviderServer = szLDAP + szServer + _T("/");
}
}
else
{
szProviderServer = szLDAP;
}
DS_ATTREDITOR_BINDINGINFO attrInfo = {0};
attrInfo.dwSize = sizeof(DS_ATTREDITOR_BINDINGINFO);
attrInfo.lpfnBind = BindingCallbackFunction;
attrInfo.lParam = (LPARAM)pCredObject;
attrInfo.lpszProviderServer = const_cast<LPWSTR>((LPCWSTR)szProviderServer);
if (pConnectData->IsRootDSE())
{
attrInfo.dwFlags = DSATTR_EDITOR_ROOTDSE;
}
if (pConnectData->IsGC())
{
attrInfo.dwFlags |= DSATTR_EDITOR_GC;
}
hr = m_spIDsAttributeEditor->Initialize(m_pADs, &attrInfo, this);
}
if (!pConnectData->IsRootDSE() && !pConnectData->IsGC())
{
if (pCredObject->UseCredentials())
{
CString szUsername;
EncryptedString password;
WCHAR* szPassword = NULL;
pCredObject->GetUsername(szUsername);
password = pCredObject->GetPassword();
// Shouldn't happen, but let's check...
ASSERT(password.GetLength() <= MAX_PASSWORD_LENGTH);
szPassword = password.GetClearTextCopy();
// If we ran out of memory just pass a NULL pwd instead
// (not much else one can do w/in constructor).
m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
lpszServer,
szUsername,
szPassword,
DSSI_NO_FILTER,
this);
// Clean up clear text copies (call even if we ran
// out of memory and cleartext == NULL).
password.DestroyClearTextCopy(szPassword);
}
else
{
m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
NULL,
NULL,
NULL,
DSSI_NO_FILTER,
this);
}
}
}
else
{
if (!pConnectData->IsRootDSE() && !pConnectData->IsGC())
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
// Create the acl editor even if we were not successful binding, because
// the object may be deny read and we would still want the acl editor
if (pCredObject->UseCredentials())
{
CString szUsername;
EncryptedString password;
WCHAR* szPassword = NULL;
pCredObject->GetUsername(szUsername);
password = pCredObject->GetPassword();
// Shouldn't happen, but let's check...
ASSERT(password.GetLength() <= MAX_PASSWORD_LENGTH);
szPassword = password.GetClearTextCopy();
// If we ran out of memory just pass a NULL pwd instead
// (not much else one can do w/in constructor).
m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
lpszServer,
szUsername,
szPassword,
DSSI_NO_FILTER,
this);
// Clean up clear text copies (call even if we ran
// out of memory and cleartext == NULL).
password.DestroyClearTextCopy(szPassword);
}
else
{
m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
NULL,
NULL,
NULL,
DSSI_NO_FILTER,
this);
}
return;
}
}
}
}
HRESULT CADSIEditPropertyPageHolder::OnAddPage(int nPage, CPropertyPageBase* pPage)
{
HRESULT hr = S_OK;
if (nPage == 0)
{
//
// Add the advanced editor page
//
HPROPSHEETPAGE hAttrPage = NULL;
if (m_spIDsAttributeEditor != NULL)
{
hr = m_spIDsAttributeEditor->GetPage(&hAttrPage);
if (SUCCEEDED(hr))
{
hr = AddPageToSheetRaw(hAttrPage);
}
}
}
else if ( nPage == -1)
{
if (m_pAclEditorPage != NULL)
{
//
// add the ACL editor page after the last, if present
//
HPROPSHEETPAGE hPage = m_pAclEditorPage->CreatePage();
if (hPage == NULL)
{
return E_FAIL;
}
//
// add the raw HPROPSHEETPAGE to sheet, not in the list
//
hr = AddPageToSheetRaw(hPage);
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
CCreateWizPropertyPageHolder::CCreateWizPropertyPageHolder(CADSIEditContainerNode* pContainerNode,
CComponentDataObject* pComponentData, LPCWSTR lpszClass, LPCWSTR lpszServer, CAttrList* pAttrList)
: CPropertyPageHolderBase(pContainerNode, NULL, pComponentData), m_propPage(pAttrList)
{
ASSERT(pComponentData != NULL);
ASSERT(pContainerNode != NULL);
m_pContainer = pContainerNode;
ASSERT(pContainerNode == GetContainerNode());
m_bAutoDeletePages = FALSE; // we have the page as embedded member
m_propPage.SetClass(lpszClass);
m_propPage.SetServer(lpszServer);
m_propPage.SetConnectionData(pContainerNode->GetADsObject()->GetConnectionNode()->GetConnectionData());
AddPageToList((CPropertyPageBase*)&m_propPage);
}