//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: editorui.cpp // //-------------------------------------------------------------------------- #include "pch.h" #include #include "resource.h" #include "attredit.h" #include "adsiedit.h" #include "editor.h" #include "editorui.h" #include "snapdata.h" #include "common.h" #include #include // 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(pTreeNode); if (pContNode == NULL) { CADSIEditLeafNode* pLeafNode = dynamic_cast(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 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((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); }