//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: domain.cpp // //-------------------------------------------------------------------------- #include "preDNSsn.h" #include #include "resource.h" #include "dnsutil.h" #include "DNSSnap.h" #include "snapdata.h" #include "server.h" #include "domain.h" #include "record.h" #include "zone.h" #include "delegwiz.h" #ifdef DEBUG_ALLOCATOR #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif BOOL _match(LPCWSTR lpszNSName, CDNS_A_RecordNode* pARecordNode) { TRACE(_T("NS %s A %s\n"), lpszNSName, pARecordNode->GetString(0)); return DnsNameCompare_W((LPWSTR)lpszNSName, (LPWSTR)pARecordNode->GetString(0)); } ///////////////////////////////////////////////////////////////////////// // CNewDomainDialog class CNewDomainDialog : public CHelpDialog { // Construction public: CNewDomainDialog(CDNSDomainNode* pParentDomainNode, CComponentDataObject* pComponentData); enum { IDD = IDD_DOMAIN_ADDNEWDOMAIN }; // Implementation protected: virtual BOOL OnInitDialog(); virtual void OnOK(); afx_msg void OnEditChange(); afx_msg void OnIPv4CtrlChange(); afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); DECLARE_MESSAGE_MAP() private: CDNSDomainNode* m_pParentDomainNode; CComponentDataObject* m_pComponentData; CEdit* GetDomainEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_DOMAIN_NAME);} CDNSIPv4Control* GetDomainIPv4Ctrl() { return (CDNSIPv4Control*)GetDlgItem(IDC_IPEDIT_DOMAIN_NAME);} CString m_szDomainName; BOOL m_bAdvancedView; int m_nOctects; int m_nUTF8ParentLen; }; BEGIN_MESSAGE_MAP(CNewDomainDialog, CHelpDialog) ON_EN_CHANGE(IDC_EDIT_DOMAIN_NAME,OnEditChange) ON_EN_CHANGE(IDC_IPEDIT_DOMAIN_NAME, OnIPv4CtrlChange) END_MESSAGE_MAP() CNewDomainDialog::CNewDomainDialog(CDNSDomainNode* pParentDomainNode, CComponentDataObject* pComponentData) : CHelpDialog(CNewDomainDialog::IDD, pComponentData) { ASSERT(pParentDomainNode != NULL); ASSERT(pComponentData != NULL); m_pParentDomainNode = pParentDomainNode; m_pComponentData = pComponentData; m_bAdvancedView = TRUE; m_nOctects = -1; // invalid if advanced view m_nUTF8ParentLen = UTF8StringLen(pParentDomainNode->GetFullName()); } BOOL CNewDomainDialog::OnInitDialog() { CHelpDialog::OnInitDialog(); // move the edit box in place of the IP control CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl(); CEdit* pNameEdit = GetDomainEdit(); pNameEdit->SetLimitText(MAX_DNS_NAME_LEN - m_nUTF8ParentLen - 1); CRect editRect; pNameEdit->GetWindowRect(editRect); ScreenToClient(editRect); CRect ipRect; pNameIPCtrl->GetWindowRect(ipRect); ScreenToClient(ipRect); ipRect.bottom = editRect.top + ipRect.Height(); ipRect.right = editRect.left + ipRect.Width(); ipRect.top = editRect.top; ipRect.left = editRect.left; pNameIPCtrl->MoveWindow(ipRect,TRUE); // determine if we need/can have advanced view CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData(); ASSERT(pRootData != NULL); m_bAdvancedView = pRootData->IsAdvancedView(); // force advanced view if we are in a forward lookup zone if (!(m_pParentDomainNode->GetZoneNode()->IsReverse())) m_bAdvancedView = TRUE; // determine if we can have a normal view representation CString szDomainName = m_pParentDomainNode->GetFullName(); if (!m_bAdvancedView) { // to have normal view we have to have a valid arpa suffix BOOL bArpa = RemoveInAddrArpaSuffix(szDomainName.GetBuffer(1)); szDomainName.ReleaseBuffer(); // got "77.80.55.157" if (!bArpa) { m_bAdvancedView = TRUE; // no need to toggle } else { m_nOctects = ReverseIPString(szDomainName.GetBuffer(1)); szDomainName.ReleaseBuffer(); // finally got "157.55.80.77" // to have a normal view representation we cannot // have more than 2 octects if (m_nOctects > 2) { m_bAdvancedView = TRUE; // force advanced for classless } else { ASSERT(m_nOctects > 0); switch(m_nOctects) { case 1: // e.g. "157", now "157._" szDomainName += _T(".0.0"); // got "157._.0.0" break; case 2: // e.g. "157.55" szDomainName += _T(".0"); // got "157.55._.0" break; }; // set the IP control with IP mask value IP_ADDRESS ipAddr = IPStringToAddr(szDomainName); ASSERT(ipAddr != INADDR_NONE); pNameIPCtrl->SetIPv4Val(ipAddr); for (int k=0; k<4; k++) pNameIPCtrl->EnableField(k, k == m_nOctects); } } } // if (!m_bAdvancedView) // toggle text in static control CDNSToggleTextControlHelper staticTextToggle; UINT pnButtonStringIDs[2] = { IDS_NEW_DOMAIN_INST1, IDS_NEW_DOMAIN_INST2 }; VERIFY(staticTextToggle.Init(this, IDC_STATIC_TEXT, pnButtonStringIDs)); staticTextToggle.SetToggleState(m_bAdvancedView); // // enable/hide appropriate controls // if (m_bAdvancedView) { pNameIPCtrl->EnableWindow(FALSE); pNameIPCtrl->ShowWindow(FALSE); } else { pNameEdit->EnableWindow(FALSE); pNameEdit->ShowWindow(FALSE); } GetDlgItem(IDOK)->EnableWindow(!m_bAdvancedView); return TRUE; // return TRUE unless you set the focus to a control } void CNewDomainDialog::OnEditChange() { ASSERT(m_bAdvancedView); // // Get new name from control // GetDomainEdit()->GetWindowText(m_szDomainName); // // Trim white space // m_szDomainName.TrimLeft(); m_szDomainName.TrimRight(); // // Enable OK button if its a valid name // CString szFullDomainName; if (_wcsicmp(m_pParentDomainNode->GetFullName(), L".") == 0) { // // If the parent domain is the root zone just check the name followed by a '.' // szFullDomainName.Format(L"%s.", m_szDomainName); } else { // // Else append the parent domain name to the new name // szFullDomainName.Format(L"%s.%s", m_szDomainName, m_pParentDomainNode->GetFullName()); } // // Get server flags // DWORD dwNameChecking = m_pParentDomainNode->GetServerNode()->GetNameCheckFlag(); // // Is valid? // BOOL bIsValidName = (0 == ValidateDnsNameAgainstServerFlags(szFullDomainName, DnsNameDomain, dwNameChecking)); GetDlgItem(IDOK)->EnableWindow(bIsValidName); } void CNewDomainDialog::OnIPv4CtrlChange() { ASSERT(!m_bAdvancedView); CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl(); DWORD dwArr[4]; pNameIPCtrl->GetArray(dwArr, 4); BOOL bEmpty = (dwArr[m_nOctects] == FIELD_EMPTY); if (!bEmpty) { ASSERT(dwArr[m_nOctects] <= 255); m_szDomainName.Format(_T("%d"), dwArr[m_nOctects]); } GetDlgItem(IDOK)->EnableWindow(!bEmpty); } void CNewDomainDialog::OnOK() { RECORD_SEARCH recordSearch = RECORD_NOT_FOUND; CDNSDomainNode* pNewParentDomain = NULL; CString szFullRecordName = m_szDomainName + L"." + m_pParentDomainNode->GetFullName(); CString szNonExistentDomain; recordSearch = m_pParentDomainNode->GetZoneNode()->DoesContain(szFullRecordName, m_pComponentData, &pNewParentDomain, szNonExistentDomain, TRUE); if (recordSearch == RECORD_NOT_FOUND && pNewParentDomain != NULL) { DNS_STATUS err = pNewParentDomain->CreateSubdomain(m_szDomainName,m_pComponentData); if (err != 0) { // creation error, warn the user and prompt again DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE); CEdit* pDomainNameEdit = GetDomainEdit(); pDomainNameEdit->SetSel(0,-1); pDomainNameEdit->SetFocus(); return; } } else if (recordSearch == NON_EXISTENT_SUBDOMAIN && pNewParentDomain != NULL) { CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData(); // // Create the node on the server // CDNSDomainNode* pNewDomainNode = pNewParentDomain->CreateSubdomainNode(); if (pNewDomainNode == NULL) { ASSERT(pNewDomainNode != NULL); return; } pNewParentDomain->SetSubdomainName(pNewDomainNode, m_szDomainName, pRootData->IsAdvancedView()); // // tell the newly created object to write to the server // DNS_STATUS err = pNewDomainNode->Create(); if (err != 0) { DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE); return; } if (!szNonExistentDomain.IsEmpty()) { // // Create the first subdomain because the current domain is already enumerated // so we have to start the remaining enumeration at the new subdomain that is needed // CDNSDomainNode* pSubdomainNode = pNewParentDomain->CreateSubdomainNode(); ASSERT(pSubdomainNode != NULL); pNewParentDomain->SetSubdomainName(pSubdomainNode, szNonExistentDomain, pRootData->IsAdvancedView()); VERIFY(pNewParentDomain->AddChildToListAndUISorted(pSubdomainNode, m_pComponentData)); m_pComponentData->SetDescriptionBarText(pNewParentDomain); // // I don't care what the results of this are, I am just using it // to do the expansion to the new record // recordSearch = pSubdomainNode->GetZoneNode()->DoesContain(szFullRecordName, m_pComponentData, &pNewParentDomain, szNonExistentDomain, TRUE); } } else if (recordSearch == RECORD_NOT_FOUND_AT_THE_NODE) { // // Do nothing since this is a domain and it already exists // } else { DNS_STATUS err = m_pParentDomainNode->CreateSubdomain(m_szDomainName,m_pComponentData); if (err != 0) { // creation error, warn the user and prompt again DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE); CEdit* pDomainNameEdit = GetDomainEdit(); pDomainNameEdit->SetSel(0,-1); pDomainNameEdit->SetFocus(); return; } } CHelpDialog::OnOK(); } ///////////////////////////////////////////////////////////////////////// // CDNSDomainQueryObj class CDNSDomainMsg : public CObjBase { }; BOOL CDNSDomainQueryObj::Enumerate() { USES_CONVERSION; TRACE(_T("CDNSDomainQueryObj::Enumerate(): Server <%s> Zone/Domain %s Enumerating\n"), (LPCTSTR)m_szServerName, (LPCTSTR)m_szNodeName); DNS_STATUS err = 0; // if needed, get the zone info if (m_bIsZone && !m_bCache) { CDNSZoneInfoEx* pZoneInfo = new CDNSZoneInfoEx; err = pZoneInfo->Query(m_szServerName, m_szFullNodeName, m_dwServerVersion); if (err != 0) { delete pZoneInfo; pZoneInfo = NULL; OnError(err); return FALSE; // no need to enumerate if we have no zone info } else { VERIFY(AddQueryResult(pZoneInfo)); } } // if executing a query for a specific RR type, just do it right away if (m_wRecordType != DNS_TYPE_ALL) { // we assume that a type specific query does not have filtering enabled ASSERT(m_bGetAll); ASSERT(m_nFilterOption == DNS_QUERY_FILTER_DISABLED); err = EnumerateFiltered(m_wRecordType); if (err != 0) OnError(err); return FALSE; // we are done } // DO A MULTI PASS QUERY m_bFirstPass = TRUE; // there are items that cannot be filtered out for consistency // (zone info, SOA, Ns, etc.), so we disable any filtering while // getting them BOOL bGetAllOld = m_bGetAll; BOOL nFilterOptionOld = m_nFilterOption; m_bGetAll = TRUE; m_nFilterOption = DNS_QUERY_FILTER_DISABLED; // only zones or the cache have SOA RR's if (m_bIsZone || m_bCache) { err = EnumerateFiltered(DNS_TYPE_SOA); if (err != 0) { OnError(err); return FALSE; } } // only zones have WINS and NBSTAT RR's if (m_bIsZone) { if (m_bReverse) err = EnumerateFiltered(DNS_TYPE_NBSTAT); else err = EnumerateFiltered(DNS_TYPE_WINS); if (err != 0) { OnError(err); return FALSE; } } // need also to check for NS (zone or delegation) err = EnumerateFiltered(DNS_TYPE_NS); if (err != 0) { OnError(err); return FALSE; } // add a message in the queue to signal we are done with // the first phase AddQueryResult(new CDNSDomainMsg); // now query again, for all RR's, but need to filter the // known types out m_bFirstPass = FALSE; // restore the filtering parameters we had before m_bGetAll = bGetAllOld; m_nFilterOption = nFilterOptionOld; err = EnumerateFiltered(DNS_TYPE_ALL); if (err != 0) OnError(err); return FALSE; } DNS_STATUS CDNSDomainQueryObj::EnumerateFiltered(WORD wRecordType) { DWORD dwSelectFlags = m_dwSelectFlags; // for single type queries, we do not want subfolders if (wRecordType != DNS_TYPE_ALL) dwSelectFlags |= DNS_RPC_VIEW_NO_CHILDREN; return CDNSDomainNode::EnumerateNodes(m_szServerName, m_szZoneName.IsEmpty() ? NULL : (LPCWSTR)m_szZoneName, m_szNodeName, m_szFullNodeName, wRecordType, dwSelectFlags, m_bIsZone, m_bReverse, m_bAdvancedView, this); } BOOL CDNSDomainQueryObj::CanAddRecord(WORD wRecordType, LPCWSTR lpszRecordName) { if (m_nFilterOption == DNS_QUERY_FILTER_DISABLED) return TRUE; // we have no filtering at all // determine if this is a special record type for filtered queries BOOL bSpecialType = (wRecordType == DNS_TYPE_SOA) || (wRecordType == DNS_TYPE_NS) || (wRecordType == DNS_TYPE_WINS) || (wRecordType == DNS_TYPE_NBSTAT); // in the first pass only special types allowed if (m_bFirstPass) return bSpecialType; // in the second pass do not allow special types if (!m_bFirstPass && bSpecialType) return FALSE; // we are left with normal types, apply the filtering, if required if (m_nFilterOption == DNS_QUERY_FILTER_NONE) return TRUE; // allow all // need to match the record name return MatchName(lpszRecordName); } ///////////////////////////////////////////////////////////////////////// // CDNSDomainNode BEGIN_TOOLBAR_MAP(CDNSDomainNode) TOOLBAR_EVENT(toolbarNewRecord, OnNewRecord) END_TOOLBAR_MAP() // {720132BA-44B2-11d1-B92F-00A0C9A06D2D} const GUID CDNSDomainNode::NodeTypeGUID = { 0x720132ba, 0x44b2, 0x11d1, { 0xb9, 0x2f, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } }; CDNSDomainNode::CDNSDomainNode(BOOL bDelegation) { m_bDelegation = bDelegation; m_pZoneNode = NULL; m_pNSRecordNodeList = new CDNS_NS_RecordNodeList; ASSERT(m_pNSRecordNodeList != NULL); m_bHasDataForPropPages = FALSE; } CDNSDomainNode::~CDNSDomainNode() { TRACE(_T("~CDNSDomainNode(), name <%s>\n"),GetDisplayName()); ASSERT(m_pNSRecordNodeList != NULL); delete m_pNSRecordNodeList; m_pNSRecordNodeList = NULL; } DWORD CDNSDomainNode::GetDefaultTTL() { if ( (m_pZoneNode != NULL) && (m_pZoneNode->GetZoneType() != DNS_ZONE_TYPE_CACHE) ) return m_pZoneNode->GetSOARecordMinTTL(); else return (DWORD)0; // no info available from SOA RR } void CDNSDomainNode::SetFullDNSName(BOOL bIsZone, BOOL, LPCTSTR lpszNodeName, LPCTSTR lpszParentFullName) { ASSERT(lpszNodeName != NULL); ASSERT(lpszParentFullName != NULL); if (bIsZone) { // // the two names have to be the same, zone parent of itself // ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) == 0); m_szFullName = lpszParentFullName; } else // it is a domain { ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) != 0); // // chain the node name to the parent full name to get the node's full name // if (lpszParentFullName[0] == L'.' ) { // // if parent is "." and name is "bar", get "bar.": this is the case for the root // if parent is ".com" and name is "bar", get "bar.com": // m_szFullName.Format(_T("%s%s"), lpszNodeName,lpszParentFullName); } else { // // if parent is "foo.com" and name is "bar", get "bar.foo.com" // m_szFullName.Format(_T("%s.%s"), lpszNodeName,lpszParentFullName); } } TRACE(_T("CDNSDomainNode::SetFullDNSName() fullName = <%s>\n"), (LPCTSTR)m_szFullName); } void CDNSDomainNode::SetDisplayDNSName(BOOL bIsZone, BOOL bReverse, BOOL bAdvancedView, LPCTSTR lpszNodeName, LPCTSTR lpszParentFullName) { ASSERT(lpszNodeName != NULL); ASSERT(lpszParentFullName != NULL); if (_wcsicmp(lpszNodeName, L".") == 0) { CString szRootString; VERIFY(szRootString.LoadString(IDS_ROOT_ZONE_LABEL)); m_szDisplayName = L"." + szRootString; } else { m_szDisplayName = lpszNodeName; } if (bIsZone && bReverse && !bAdvancedView) { CDNSZoneNode::SetZoneNormalViewHelper(m_szDisplayName); } } void CDNSDomainNode::SetNames(BOOL bIsZone, BOOL bReverse, BOOL bAdvancedView, LPCTSTR lpszNodeName, LPCTSTR lpszParentFullName) { ASSERT(lpszNodeName != NULL); ASSERT(lpszParentFullName != NULL); TRACE(_T("CDNSDomainNode::SetNames(bIsZone=%d, bReverse=%d, bAdvancedView=%d, lpszNodeName=<%s>, lpszParentFullName=<%s>)\n"), bIsZone, bReverse, bAdvancedView, lpszNodeName,lpszParentFullName); SetFullDNSName(bIsZone, bReverse, lpszNodeName, lpszParentFullName); SetDisplayDNSName(bIsZone, bReverse, bAdvancedView, lpszNodeName, lpszParentFullName); } void CDNSDomainNode::ChangePTRRecordsViewOption(BOOL bAdvanced, CComponentDataObject* pComponentDataObject) { POSITION pos; for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos); // recurse down the tree CDNSDomainNode* pDomainNode = dynamic_cast(pCurrentChild); ASSERT(pDomainNode != NULL); pDomainNode->ChangePTRRecordsViewOption(bAdvanced, pComponentDataObject); } POSITION leafPos; for ( leafPos = m_leafChildList.GetHeadPosition(); leafPos != NULL; ) { CTreeNode* pCurrentLeafNode = m_leafChildList.GetNext(leafPos); CDNSRecordNodeBase* pRecordNode = dynamic_cast(pCurrentLeafNode); ASSERT(pRecordNode != NULL); if (DNS_TYPE_PTR == pRecordNode->GetType()) { CDNS_PTR_RecordNode* pPTRRecordNode = (CDNS_PTR_RecordNode*)pRecordNode; pPTRRecordNode->ChangeDisplayName(this, bAdvanced); } } } CQueryObj* CDNSDomainNode::OnCreateQuery() { // generic default setting WORD wRecordType = DNS_TYPE_ALL; DWORD dwSelectFlags = (m_pZoneNode->GetZoneType() == DNS_ZONE_TYPE_CACHE) ? DNS_RPC_VIEW_CACHE_DATA : DNS_RPC_VIEW_AUTHORITY_DATA; if (IsDelegation()) { // special case the delegation: show only NS records and // will have no children shown (delegation cut) wRecordType = DNS_TYPE_NS; dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA | DNS_RPC_VIEW_NO_CHILDREN; //dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA | // DNS_RPC_VIEW_NO_CHILDREN | DNS_RPC_VIEW_ADDITIONAL_DATA; } BOOL bCache = GetZoneNode()->GetZoneType() == DNS_ZONE_TYPE_CACHE; LPCWSTR lpszZoneName = bCache ? NULL : m_pZoneNode->GetFullName(); CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer(); ASSERT(pRootData != NULL); CDNSDomainQueryObj* pQuery = new CDNSDomainQueryObj(GetServerNode()->GetRPCName(), lpszZoneName, GetServerNode()->GetVersion(), GetDisplayName(), m_szFullName, wRecordType, dwSelectFlags, IsZone(), GetZoneNode()->IsReverse(), bCache, pRootData->IsAdvancedView()); // delegations will not have any filtering option (data consistency) if (!IsDelegation()) { pQuery->SetFilterOptions(pRootData->GetFilter()); } return pQuery; } BOOL CDNSDomainNode::OnRefresh(CComponentDataObject* pComponentData, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { BOOL bRet = TRUE; POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); ASSERT(pNode != NULL); CNodeList nodeList; nodeList.AddTail(pNode); if (!pNode->OnRefresh(pComponentData, &nodeList)) { bRet = FALSE; } } return bRet; } // // single selection // if (CMTContainerNode::OnRefresh(pComponentData, pNodeList)) { GetNSRecordNodeList()->RemoveAll(); m_bHasDataForPropPages = FALSE; return TRUE; } return FALSE; } void CDNSDomainNode::OnThreadExitingNotification(CComponentDataObject* pComponentDataObject) { if (!m_bHasDataForPropPages) { // never got a CDNSDomainMsg notification object // but we are done anyway, so change it back m_bHasDataForPropPages = TRUE; } // call now the base class CDNSMTContainerNode::OnThreadExitingNotification(pComponentDataObject); } void CDNSDomainNode::OnHaveData(CObjBase* pObj, CComponentDataObject* pComponentDataObject) { if (IS_CLASS(*pObj, CDNSDomainMsg)) { // special case for a "message" object sent through to update verbs TRACE(_T("Got CDNSDomainMsg\n")); delete pObj; ASSERT(!m_bHasDataForPropPages); // should get only once m_bHasDataForPropPages = TRUE; VERIFY(SUCCEEDED(pComponentDataObject->UpdateVerbState(this))); return; } if (IS_CLASS(*pObj, CDNSDomainNode)) { // assume all the child containers are derived from this class CDNSDomainNode* pDomainNode = dynamic_cast(pObj); pDomainNode->SetServerNode(GetServerNode()); pDomainNode->SetZone(m_pZoneNode); } else { OnHaveRecord(dynamic_cast(pObj), pComponentDataObject); } AddChildToListAndUI(dynamic_cast(pObj), pComponentDataObject); pComponentDataObject->SetDescriptionBarText(this); } void CDNSDomainNode::OnHaveRecord(CDNSRecordNodeBase* pRecordNode, CComponentDataObject* pComponentDataObject) { WORD wType = pRecordNode->GetType(); if (wType == DNS_TYPE_PTR) { ASSERT(pComponentDataObject != NULL); // assume this for PTR CDNSRootData* pRootData = (CDNSRootData*)pComponentDataObject->GetRootData(); ASSERT(pRootData != NULL); // if we are in normal view, have to change the // default advanced representation BOOL bAdvancedView = pRootData->IsAdvancedView(); if (!bAdvancedView) ((CDNS_PTR_RecordNode*)pRecordNode)->ChangeDisplayName(this, bAdvancedView); } else if (wType == DNS_TYPE_NS) { ASSERT(pRecordNode->IsAtTheNode()); GetNSRecordNodeList()->AddTail((CDNS_NS_RecordNode*)pRecordNode); } } BOOL CDNSDomainNode::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem2, long*) { if (pContextMenuItem2->lCommandID == IDM_SNAPIN_ADVANCED_VIEW) { pContextMenuItem2->fFlags = ((CDNSRootData*)GetRootContainer())->IsAdvancedView() ? MF_CHECKED : 0; return TRUE; } if (pContextMenuItem2->lCommandID == IDM_SNAPIN_FILTERING) { if (((CDNSRootData*)GetRootContainer())->IsFilteringEnabled()) { pContextMenuItem2->fFlags = MF_CHECKED; } return TRUE; } DWORD dwType = m_pZoneNode->GetZoneType(); BOOL bIsAutocreated = m_pZoneNode->IsAutocreated(); BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) || (dwType == DNS_ZONE_TYPE_CACHE) || (dwType == DNS_ZONE_TYPE_STUB); BOOL bIsDelegatedDomain = !IsZone() && IsDelegation(); if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain) { return FALSE; } // different add operations depending on the FWD/REV type if (!GetZoneNode()->IsReverse() && (pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_PTR)) { // do not add a PTR to a FWD lookup zone return FALSE; } if (GetZoneNode()->IsReverse() && ((pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_HOST) || (pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_MX))) { // do not add a HOST, MX, ALIAS to a REV lookup zone return FALSE; } // have the menu item added. but it might be grayed out... if (m_nState != loaded) { pContextMenuItem2->fFlags |= MF_GRAYED; } return TRUE; } HRESULT CDNSDomainNode::OnSetToolbarVerbState(IToolbar* pToolbar, CNodeList* pNodeList) { HRESULT hr = S_OK; // // Set the button state for each button on the toolbar // hr = pToolbar->SetButtonState(toolbarNewServer, ENABLED, FALSE); ASSERT(SUCCEEDED(hr)); hr = pToolbar->SetButtonState(toolbarNewZone, ENABLED, FALSE); ASSERT(SUCCEEDED(hr)); if (pNodeList->GetCount() > 1) // multiple selection { hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, FALSE); } else if (pNodeList->GetCount() == 1) // single selection { DWORD dwType = m_pZoneNode->GetZoneType(); BOOL bIsAutocreated = m_pZoneNode->IsAutocreated(); BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) || (dwType == DNS_ZONE_TYPE_CACHE) || (dwType == DNS_ZONE_TYPE_STUB); BOOL bIsDelegatedDomain = !IsZone() && IsDelegation(); BOOL bEnable = TRUE; if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain) { bEnable = FALSE; } hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, bEnable); } return hr; } BOOL CDNSDomainNode::OnSetDeleteVerbState(DATA_OBJECT_TYPES type, BOOL* pbHide, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { BOOL bRet = TRUE; BOOL bRetHide = FALSE; *pbHide = FALSE; POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); ASSERT(pNode != NULL); CNodeList nodeList; nodeList.AddTail(pNode); if (!pNode->OnSetDeleteVerbState(type, &bRetHide, &nodeList)) { bRet = FALSE; break; } if (bRetHide) { *pbHide = TRUE; } } return bRet; } *pbHide = FALSE; DWORD dwType = m_pZoneNode->GetZoneType(); BOOL bIsAutocreated = m_pZoneNode->IsAutocreated(); if (IsThreadLocked()) { return FALSE; } // // cannot delete from an autocreate zone/domain // if (bIsAutocreated) { return FALSE; } // // cannot delete from a secondary or stub zone, but can delete the zone itself // cannot delete the cache // if ( ( ( ((dwType == DNS_ZONE_TYPE_SECONDARY) || (dwType == DNS_ZONE_TYPE_STUB)) && !IsZone() ) || // subdomain of secondary ( (dwType == DNS_ZONE_TYPE_CACHE) && IsZone() ) // cache zone itself ) ) { return FALSE; } return TRUE; } BOOL CDNSDomainNode::OnSetRefreshVerbState(DATA_OBJECT_TYPES, BOOL* pbHide, CNodeList*) { *pbHide = FALSE; return !IsThreadLocked(); } HRESULT CDNSDomainNode::OnCommand(long nCommandID, DATA_OBJECT_TYPES, CComponentDataObject* pComponentData, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { return E_FAIL; } switch (nCommandID) { case IDM_DOMAIN_NEW_DOMAIN: OnNewDomain(pComponentData); break; case IDM_DOMAIN_NEW_DELEGATION: OnNewDelegation(pComponentData); break; case IDM_DOMAIN_NEW_RECORD: OnNewRecord(pComponentData, pNodeList); break; case IDM_DOMAIN_NEW_HOST: OnNewHost(pComponentData); break; case IDM_DOMAIN_NEW_ALIAS: OnNewAlias(pComponentData); break; case IDM_DOMAIN_NEW_MX: OnNewMailExchanger(pComponentData); break; case IDM_DOMAIN_NEW_PTR: OnNewPointer(pComponentData); break; case IDM_SNAPIN_ADVANCED_VIEW: ((CDNSRootData*)pComponentData->GetRootData())->OnViewOptions(pComponentData); break; case IDM_SNAPIN_FILTERING: { if(((CDNSRootData*)pComponentData->GetRootData())->OnFilteringOptions(pComponentData)) { pComponentData->SetDescriptionBarText(this); } } break; default: ASSERT(FALSE); // Unknown command! return E_FAIL; } return S_OK; } LPWSTR CDNSDomainNode::GetDescriptionBarText() { static CString szFilterEnabled; static CString szRecordsFormat; INT_PTR nContainerCount = GetContainerChildList()->GetCount(); INT_PTR nLeafCount = GetLeafChildList()->GetCount(); // // If not already loaded, then load the format string L"%d record(s)" // if (szRecordsFormat.IsEmpty()) { szRecordsFormat.LoadString(IDS_FORMAT_RECORDS); } // // Format the child count into the description bar text // m_szDescriptionBar.Format(szRecordsFormat, nContainerCount + nLeafCount); // // Add L"[Filter Activated]" if the filter is on // if(((CDNSRootData*)GetRootContainer())->IsFilteringEnabled()) { // // If not already loaded, then load the L"[Filter Activated]" string // if (szFilterEnabled.IsEmpty()) { szFilterEnabled.LoadString(IDS_FILTER_ENABLED); } m_szDescriptionBar += szFilterEnabled; } return (LPWSTR)(LPCWSTR)m_szDescriptionBar; } int CDNSDomainNode::GetImageIndex(BOOL) { int nIndex = 0; BOOL bDelegation = IsDelegation(); switch (m_nState) { case notLoaded: nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_NOT_LOADED : DOMAIN_IMAGE_NOT_LOADED; break; case loading: nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADING : DOMAIN_IMAGE_LOADING; break; case loaded: nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADED : DOMAIN_IMAGE_LOADED; break; case unableToLoad: nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_UNABLE_TO_LOAD : DOMAIN_IMAGE_UNABLE_TO_LOAD; break; case accessDenied: nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_ACCESS_DENIED : DOMAIN_IMAGE_ACCESS_DENIED; break; default: ASSERT(FALSE); } return nIndex; } void CDNSDomainNode::OnDelete(CComponentDataObject* pComponentData, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { OnMultiselectDelete(pComponentData, pNodeList); return; } UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_DELETE, this); if (IDNO == nRet || IDCANCEL == nRet) { return; } if (IsSheetLocked()) { if (!CanCloseSheets()) return; pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this); } ASSERT(!IsSheetLocked()); DNS_STATUS err = Delete(); if (err != 0) { DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_DELETE); return; } // now remove from the UI and from the cache DeleteHelper(pComponentData); delete this; // gone } void CDNSDomainNode::OnMultiselectDelete(CComponentDataObject* pComponentData, CNodeList* pNodeList) { UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_MULTI_DELETE, this); if (IDCANCEL == nRet || IDNO == nRet) { return; } DNS_STATUS* errArray = new DNS_STATUS[pNodeList->GetCount()]; if (errArray == NULL) { DNSErrorDialog(E_OUTOFMEMORY, IDS_MSG_DOMAIN_FAIL_DELETE); return; } memset(errArray, 0, sizeof(DNS_STATUS) * pNodeList->GetCount()); BOOL bErrorOccurred = FALSE; UINT idx = 0; POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pTreeNode = pNodeList->GetNext(pos); if (pTreeNode != NULL) { if (pTreeNode->IsSheetLocked()) { if (!pTreeNode->CanCloseSheets()) { idx++; continue; } pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(pTreeNode); } ASSERT(!pTreeNode->IsSheetLocked()); CDNSDomainNode* pDomainNode = dynamic_cast(pTreeNode); if (pDomainNode != NULL) { errArray[idx] = pDomainNode->Delete(); if (errArray[idx] != 0) { bErrorOccurred = TRUE; idx++; continue; } // // now remove from the UI and from the cache // pDomainNode->DeleteHelper(pComponentData); delete pDomainNode; // gone } else { // // If its not a domain node then it must be a record node // CDNSRecordNodeBase* pRecordNode = dynamic_cast(pTreeNode); if (pRecordNode != NULL) { errArray[idx] = pRecordNode->DeleteOnServerAndUI(pComponentData); if (errArray[idx] != 0) { bErrorOccurred = TRUE; idx++; continue; } delete pRecordNode; // gone } else { // // What type of node is this??? // ASSERT(FALSE); } } } idx++; } // // Now display the errors in some meaningful manner // if (bErrorOccurred) { CMultiselectErrorDialog dlg; CString szTitle; CString szCaption; CString szColumnHeader; VERIFY(szTitle.LoadString(IDS_MULTISELECT_ERROR_DIALOG_TITLE)); VERIFY(szCaption.LoadString(IDS_MULTISELECT_ERROR_DIALOG_CAPTION)); VERIFY(szColumnHeader.LoadString(IDS_MULTISELECT_ERROR_DIALOG_COLUMN_HEADER)); HRESULT hr = dlg.Initialize(pNodeList, errArray, static_cast(pNodeList->GetCount()), szTitle, szCaption, szColumnHeader); if (SUCCEEDED(hr)) { dlg.DoModal(); } } } void CDNSDomainNode::OnNewDomain(CComponentDataObject* pComponentData) { CNewDomainDialog dlg(this, pComponentData); // the dialog will do the creation dlg.DoModal(); } void CDNSDomainNode::OnNewDelegation(CComponentDataObject* pComponentData) { ASSERT(pComponentData != NULL); CDNSMTContainerNode* pContainerNode = (CDNSMTContainerNode*)GetContainer(); ASSERT(pContainerNode != NULL); CDNSDelegationWizardHolder* pHolder = new CDNSDelegationWizardHolder(pContainerNode, this, pComponentData); ASSERT(pHolder != NULL); pHolder->DoModalWizard(); } RECORD_SEARCH CDNSDomainNode::DoesContain(PCWSTR pszRecName, CComponentDataObject* pComponentData, CDNSDomainNode** ppDomainNode, CString& szNonExistentDomain, BOOL bExpandNodes) { #if TRUE CDNSNameTokenizer recordTokenizer(pszRecName); CDNSNameTokenizer domainTokenizer((IsZone()) ? GetFullName() : GetDisplayName()); if (!recordTokenizer.Tokenize(L".") || !domainTokenizer.Tokenize(L".")) { *ppDomainNode = NULL; return RECORD_NOT_FOUND; } recordTokenizer.RemoveMatchingFromTail(domainTokenizer); if (recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() == 0) { // // Record is "At the node" // *ppDomainNode = this; return RECORD_NOT_FOUND_AT_THE_NODE; } else if ((recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() != 0) || (recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() != 0)) { // // I don't understand how we got in this situation. It means we are searching in // the wrong domain. // ASSERT(FALSE); *ppDomainNode = NULL; return RECORD_NOT_FOUND; } else // recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() == 0 { // // Need to search the children lists // // // If the node hasn't been enumerated, do that now // if (!IsEnumerated()) { if (!bExpandNodes) { *ppDomainNode = this; return DOMAIN_NOT_ENUMERATED; } else { // // Expand the node // HWND hWnd = NULL; HRESULT hr = pComponentData->GetConsole()->GetMainWindow(&hWnd); ASSERT(SUCCEEDED(hr)); CWnd* pParentWnd = CWnd::FromHandle(hWnd); CLongOperationDialog dlg( new CNodeEnumerationThread(pComponentData, this), pParentWnd, IDR_SEARCH_AVI); dlg.DoModal(); } } CString szRemaining; recordTokenizer.GetRemaining(szRemaining, L"."); // // Search for domains that match the last token remaining in the record name // POSITION pos = m_containerChildList.GetHeadPosition(); while (pos != NULL) { CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos); CDNSDomainNode* pDomainNode = dynamic_cast(pCurrentChild); if (pDomainNode == NULL) { ASSERT(FALSE); continue; } if (_wcsicmp(pDomainNode->GetDisplayName(), recordTokenizer.GetTail()) == 0) { // // Found a sub-domain in the path that we have in the UI // recurse to see if it or any of its child match pszFullName // return pDomainNode->DoesContain(szRemaining, pComponentData, ppDomainNode, szNonExistentDomain, bExpandNodes); } } // // If the remaining name doesn't match a domain and there // is still a '.' in it then there is a non-existent domain // if (szRemaining.Find(L'.') != -1) { szNonExistentDomain = recordTokenizer.GetTail(); *ppDomainNode = this; return NON_EXISTENT_SUBDOMAIN; } // // Since no domains match, lets check the records // pos = m_leafChildList.GetHeadPosition(); while (pos != NULL) { CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos); if (pCurrentChild == NULL) { ASSERT(FALSE); continue; } if (_wcsicmp(pCurrentChild->GetDisplayName(), szRemaining) == 0) { // // We found the record and its in this domain // *ppDomainNode = this; return RECORD_FOUND; } } } *ppDomainNode = this; return RECORD_NOT_FOUND; #else // // The fast way that doesn't quite work // CString szDomainFullName = GetFullName(); CString szFullName = pszFullName; // // Check to see if the end of the names are equal // int iFindResult = szFullName.Find(szDomainFullName); if (iFindResult == -1) { // // If they are not we are never going to find them // *ppDomainNode = NULL; return RECORD_NOT_FOUND; } if (iFindResult == 0) { // // We found it // *ppDomainNode = this; return RECORD_FOUND; } // // Remove the matching parts plus the trailing dot // This should leave us with something like foo.bar or just foo // CString szRelativeName = szFullName.Left(iFindResult - 1); ASSERT(!szRelativeName.IsEmpty()); CString szChild; CString szRemaining; // // Now search for a dot starting on the right // iFindResult = szRelativeName.ReverseFind(L'.'); if (iFindResult == -1) { // // The relative name doesn't contain a dot so it is the child // we are looking for // szChild = szRelativeName; } else { szChild = szRelativeName.Right(szRelativeName.GetLength() - iFindResult - 1); szRemaining = szRelativeName; } // // If the node hasn't been enumerated, do that now // if (!IsEnumerated()) { if (!bExpandNodes) { *ppDomainNode = this; return DOMAIN_NOT_ENUMERATED; } else { // // Expand the node // HWND hWnd = NULL; HRESULT hr = pComponentData->GetConsole()->GetMainWindow(&hWnd); ASSERT(SUCCEEDED(hr)); CWnd* pParentWnd = CWnd::FromHandle(hWnd); CLongOperationDialog dlg( new CNodeEnumerationThread(pComponentData, this), pParentWnd, IDR_SEARCH_AVI); dlg.DoModal(); } } // // Search for domains that match this name // POSITION pos = m_containerChildList.GetHeadPosition(); while (pos != NULL) { CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos); CDNSDomainNode* pDomainNode = dynamic_cast(pCurrentChild); if (pDomainNode == NULL) { ASSERT(FALSE); continue; } if (_wcsicmp(pDomainNode->GetDisplayName(), szChild) == 0) { // // Found a sub-domain in the path that we have in the UI // recurse to see if it or any of its child match pszFullName // return pDomainNode->DoesContain(pszFullName, pComponentData, ppDomainNode, szNonExistentDomain, bExpandNodes); } } // // Since no domains match, lets check the records // pos = m_leafChildList.GetHeadPosition(); while (pos != NULL) { CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos); if (pCurrentChild == NULL) { ASSERT(FALSE); continue; } if (_wcsicmp(pCurrentChild->GetDisplayName(), szChild) == 0) { // // We found the record and its in this domain // *ppDomainNode = this; return RECORD_FOUND; } } // // Well, we didn't find the record, If the remaining part of the name // still contains a '.' then we know the domain the that contains the // record is not in the UI so return NULL. If there isn't a '.' then // we are at the correct level but just couldn't find the record. Return // this domain. // if (szRemaining.Find(L'.') == -1) { *ppDomainNode = this; return RECORD_NOT_FOUND; } else { // // We were not able to find a subdomain that the record should be in // *ppDomainNode = this; return NON_EXISTENT_SUBDOMAIN; } return RECORD_NOT_FOUND; #endif } CDNSDomainNode* CDNSDomainNode::FindSubdomainNode(LPCTSTR lpszSubdomainNode) { // // assume the string is the name of the subnode as FQDN // // // Check the current node first since it could be zone that is a delegation of // one of the protocol domains // if (_wcsicmp(GetFullName(), lpszSubdomainNode) == 0) { return this; } POSITION pos; for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos); CDNSDomainNode* pSubDomainNode = dynamic_cast(pCurrentChild); ASSERT(pSubDomainNode != NULL); if (_wcsicmp(pSubDomainNode->GetFullName(), lpszSubdomainNode) == 0) { return pSubDomainNode; } } return NULL; // not found } CDNSDomainNode* CDNSDomainNode::CreateSubdomainNode(BOOL bDelegation) { CDNSDomainNode* pNode = new CDNSDomainNode(bDelegation); pNode->SetServerNode(GetServerNode()); ASSERT(m_pZoneNode != NULL); pNode->SetZone(m_pZoneNode); return pNode; } void CDNSDomainNode::SetSubdomainName(CDNSDomainNode* pSubdomainNode, LPCTSTR lpszSubdomainName, BOOL bAdvancedView) { ASSERT(m_pZoneNode != NULL); ASSERT(pSubdomainNode != NULL); BOOL bReverse = GetZoneNode()->IsReverse(); pSubdomainNode->SetNames(FALSE, bReverse, bAdvancedView, lpszSubdomainName, GetFullName()); } DNS_STATUS CDNSDomainNode::CreateSubdomain(CDNSDomainNode* pSubdomainNode, CComponentDataObject* pComponentData) { // tell the newly created object to write to the server DNS_STATUS err = pSubdomainNode->Create(); if (err == 0) { // success, add to the UI VERIFY(AddChildToListAndUI(pSubdomainNode, pComponentData)); pComponentData->SetDescriptionBarText(this); } return err; } DNS_STATUS CDNSDomainNode::CreateSubdomain(LPCTSTR lpszDomainName, CComponentDataObject* pComponentData) { CDNSDomainNode* pSubdomainNode = CreateSubdomainNode(); ASSERT(pSubdomainNode != NULL); CDNSRootData* pRootData = (CDNSRootData*)pComponentData->GetRootData(); SetSubdomainName(pSubdomainNode, lpszDomainName, pRootData->IsAdvancedView()); // tell the newly created object to write to the server DNS_STATUS err = CreateSubdomain(pSubdomainNode, pComponentData); if (err != 0) { // something went wrong, bail out delete pSubdomainNode; } return err; } void CDNSDomainNode::OnNewRecordHelper(CComponentDataObject* pComponentData, WORD wType) { ASSERT(pComponentData != NULL); if (wType == 0) { CSelectDNSRecordTypeDialog dlg(this, pComponentData); dlg.DoModal(); } else { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString szTitle; szTitle.LoadString(IDS_NEW_RECORD_TITLE); CDNSRecordPropertyPageHolder recordHolder(this, NULL, pComponentData, wType); recordHolder.DoModalDialog(szTitle); } } HRESULT CDNSDomainNode::OnNewRecord(CComponentDataObject* pComponentData, CNodeList* pNodeList) { ASSERT(pNodeList->GetCount() == 1); OnNewRecordHelper(pComponentData, 0); return S_OK; } void CDNSDomainNode::OnNewHost(CComponentDataObject* pComponentData) { //AFX_MANAGE_STATE(AfxGetStaticModuleState()); //OnNewRecordHelper(pComponentData, DNS_TYPE_A); CNewHostDialog dlg(this, pComponentData); dlg.DoModal(); } void CDNSDomainNode::OnNewAlias(CComponentDataObject* pComponentData) { OnNewRecordHelper(pComponentData, DNS_TYPE_CNAME); } void CDNSDomainNode::OnNewMailExchanger(CComponentDataObject* pComponentData) { OnNewRecordHelper(pComponentData, DNS_TYPE_MX); } void CDNSDomainNode::OnNewPointer(CComponentDataObject* pComponentData) { OnNewRecordHelper(pComponentData, DNS_TYPE_PTR); } ////////////////////////////////////////////////////////////////////////////////// // display of property pages BOOL CDNSDomainNode::HasPropertyPages(DATA_OBJECT_TYPES, BOOL* pbHideVerb, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { *pbHideVerb = TRUE; return FALSE; } *pbHideVerb = FALSE; // always show the verb if (!m_bHasDataForPropPages) return FALSE; // cannot have property pages only in loaded state //if (m_nState != loaded) // return FALSE; // have pages if it is a delegation return IsDelegation(); } HRESULT CDNSDomainNode::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, CNodeList* pNodeList) { ASSERT(pNodeList->GetCount() == 1); // multi-select not supported ASSERT(m_bHasDataForPropPages); ASSERT(IsDelegation() || GetZoneNode()->IsDSIntegrated()); if (GetSheetCount() > 0) { CComponentDataObject* pComponentDataObject = ((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject(); ASSERT(pComponentDataObject != NULL); pComponentDataObject->GetPropertyPageHolderTable()->BroadcastSelectPage(this, DOMAIN_HOLDER_NS); return S_OK; } return CreatePropertyPagesHelper(lpProvider, handle, DOMAIN_HOLDER_NS); } void CDNSDomainNode::Show(BOOL bShow, CComponentDataObject* pComponentData) { CDNSMTContainerNode::Show(bShow, pComponentData); if (!bShow) GetNSRecordNodeList()->RemoveAll(); } HRESULT CDNSDomainNode::CreatePropertyPagesHelper(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, long) { CComponentDataObject* pComponentDataObject = ((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject(); ASSERT(pComponentDataObject != NULL); CDNSDomainPropertyPageHolder* pHolder = new CDNSDomainPropertyPageHolder((CDNSDomainNode*)GetContainer(), this, pComponentDataObject); ASSERT(pHolder != NULL); pHolder->SetSheetTitle(IDS_PROP_SHEET_TITLE_FMT, this); return pHolder->CreateModelessSheet(lpProvider, handle); } ////////////////////////////////////////////////////////////////////////////////// // Record Sorting in result pane int FieldCompareHelper(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol) { int iRet = 0; if (nCol == N_HEADER_NAME) { // // If the name column is selected we have to sort PTR records by their // address // CDNS_PTR_RecordNode* pRecNodeA = dynamic_cast(pNodeA); CDNS_PTR_RecordNode* pRecNodeB = dynamic_cast(pNodeB); if (pRecNodeA == NULL && pRecNodeB == NULL) { // // Neither node is a PTR record, process normally // LPCTSTR lpszA = pNodeA->GetString(nCol); LPCTSTR lpszB = pNodeB->GetString(nCol); // // cannot process NULL strings, have to use "" // if (lpszA == NULL || lpszB == NULL) { ASSERT(FALSE); return -1; } iRet = _wcsicmp(lpszA, lpszB); } else if (pRecNodeA == NULL) { // // Push non PTR records down in the list // iRet = 1; } else if (pRecNodeB == NULL) { // // Push non PTR records down in the list // iRet = -1; } else { // // Both nodes are PTR records, compare their Addresses // Subtract one from the other // This will result in < 0 returned if the first one is less than the second // 0 if they are equal, and > 0 if the first is greater than the second // LPCWSTR lpszNameA, lpszNameB; lpszNameA = pRecNodeA->GetTrueRecordName(); lpszNameB = pRecNodeB->GetTrueRecordName(); if (lpszNameA == NULL) { return -1; } if (lpszNameB == NULL) { return 1; } DWORD dwAddrA, dwAddrB; int iConverts = swscanf(lpszNameA, L"%d", &dwAddrA); if (iConverts != 1) { return -1; } iConverts = swscanf(lpszNameB, L"%d", &dwAddrB); if (iConverts != 1) { return 1; } iRet = dwAddrA - dwAddrB; } } else if (nCol == N_HEADER_DATA) { // // If the data column is selected we have to check the record type so // that we can sort by IP address // CDNS_A_RecordNode* pRecNodeA = dynamic_cast(pNodeA); CDNS_A_RecordNode* pRecNodeB = dynamic_cast(pNodeB); if (pRecNodeA == NULL && pRecNodeB == NULL) { // // Neither node is an A record, process normally // LPCTSTR lpszA = pNodeA->GetString(nCol); LPCTSTR lpszB = pNodeB->GetString(nCol); // // cannot process NULL strings, have to use "" // if (lpszA == NULL || lpszB == NULL) { ASSERT(FALSE); return -1; } iRet = _wcsicmp(lpszA, lpszB); } else if (pRecNodeA == NULL) { // // Push non A records down in the list // iRet = 1; } else if (pRecNodeB == NULL) { // // Push non A records down in the list // iRet = -1; } else { // // Both nodes are A records, compare their IP Addresses // Subtract one from the other // This will result in < 0 returned if the first one is less than the second // 0 if they are equal, and > 0 if the first is greater than the second // DWORD dwIPA, dwIPB; dwIPA = pRecNodeA->GetIPAddress(); dwIPB = pRecNodeB->GetIPAddress(); UINT nOctetCount = 0; iRet = 0; while (iRet == 0 && nOctetCount < 4) { iRet = (dwIPA & 0xff) - (dwIPB & 0xff); dwIPA = dwIPA >> 8; dwIPB = dwIPB >> 8; ++nOctetCount; } } } else { LPCTSTR lpszA = pNodeA->GetString(nCol); LPCTSTR lpszB = pNodeB->GetString(nCol); // // cannot process NULL strings, have to use "" // if (lpszA == NULL || lpszB == NULL) { ASSERT(FALSE); return -1; } iRet = _wcsicmp(lpszA, lpszB); } return iRet; } int CDNSDomainNode::Compare(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol, long) { // sorting rules for secondary fields int nColSec = N_HEADER_TYPE; int nColThird = N_HEADER_DATA; switch (nCol) { case N_HEADER_NAME: nColSec = N_HEADER_TYPE; nColThird = N_HEADER_DATA; break; case N_HEADER_TYPE: nColSec = N_HEADER_NAME; nColThird = N_HEADER_DATA; break; case N_HEADER_DATA: nColSec = N_HEADER_NAME; nColThird = N_HEADER_TYPE; break; default: ASSERT(FALSE); } int nResult = FieldCompareHelper(pNodeA, pNodeB, nCol); if (nResult != 0) return nResult; nResult = FieldCompareHelper(pNodeA, pNodeB, nColSec); if (nResult != 0) return nResult; return FieldCompareHelper(pNodeA, pNodeB, nColThird); } ////////////////////////////////////////////////////////////////////////////////// // NS record bulk manipulation // function to the user for confirmation on editing of A records // associated with an NS record BOOL _ConfirmEditAction(CDNSRecordNodeEditInfo* pInfo, BOOL bAsk) { if (!bAsk) return TRUE; // silently do it AFX_MANAGE_STATE(AfxGetStaticModuleState()); ASSERT(pInfo->m_pRecord->GetType() == DNS_TYPE_A); ASSERT(pInfo->m_pRecord != NULL); CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pInfo->m_pRecordNode; // load format message CString szFmt; szFmt.LoadString(IDS_MSG_RECORD_DEL_A_FROM_NS); // compose message CString szMsg; szMsg.Format((LPCWSTR)szFmt, pARecordNode->GetString(0), pARecordNode->GetString(2)); return (IDYES == DNSMessageBox(szMsg, MB_YESNO | MB_ICONWARNING ) ); } void CDNSDomainNode::GetNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNSInfoList) { ASSERT(pNSInfoList != NULL); if (!pNSInfoList->IsEmpty()) { ASSERT(FALSE); // should never happen pNSInfoList->RemoveAllNodes(); } CDNS_NS_RecordNodeList* pNodeList = GetNSRecordNodeList(); // for each NS record in the list, create an entry in the info list POSITION pos; for( pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CDNS_NS_RecordNode* pCurrNode = pNodeList->GetNext(pos); ASSERT(pCurrNode != NULL); CDNSRecordNodeEditInfo* pNSNodeInfo = new CDNSRecordNodeEditInfo(); if (pNSNodeInfo) { // set the data for the NS record, already in the list, so we do now own the memory pNSNodeInfo->CreateFromExistingRecord(pCurrNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/); // for the current NS record, find the associated A records FindARecordsFromNSInfo(pCurrNode->GetString(2),pNSNodeInfo->m_pEditInfoList); pNSInfoList->AddTail(pNSNodeInfo); } } } BOOL CDNSDomainNode::HasNSRecords() { return GetNSRecordNodeList()->GetCount() > 0; } BOOL CDNSDomainNode::UpdateNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNewInfoList, CComponentDataObject* pComponentData) { ASSERT(pNewInfoList != NULL); // return false if at least one operation failed BOOL bRes = TRUE; CDNS_NS_RecordNodeList* pNSRecordNodeList = GetNSRecordNodeList(); // clear the current state in this domain object pNSRecordNodeList->RemoveAll(); // rebuild the current list from the new one, while applying the changes POSITION pos; for ( pos = pNewInfoList->GetHeadPosition(); pos != NULL; ) { CDNSRecordNodeEditInfo* pCurrentInfo = pNewInfoList->GetNext(pos); ASSERT(pCurrentInfo->m_pRecordNode != NULL); ASSERT(pCurrentInfo->m_pRecord != NULL); switch (pCurrentInfo->m_action) { case CDNSRecordNodeEditInfo::add: case CDNSRecordNodeEditInfo::edit: { if (pCurrentInfo->Update(this, pComponentData) == 0) { ASSERT(pCurrentInfo->m_pRecordNode->GetType() == DNS_TYPE_NS); pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode); pCurrentInfo->m_bOwnMemory = FALSE; // relinquish ownership } else { bRes = FALSE; } } break; case CDNSRecordNodeEditInfo::remove: { if (pCurrentInfo->m_bExisting) { if (pCurrentInfo->Remove(this, pComponentData) != 0) bRes = FALSE; } } break; case CDNSRecordNodeEditInfo::none: // // Do nothing if the the node has been added and then removed without having been applied // break; default: { ASSERT(pCurrentInfo->m_bOwnMemory == FALSE); ASSERT(pCurrentInfo->m_action == CDNSRecordNodeEditInfo::unchanged); // // We still have to update the NS record because the server needs to // update the record in memory (bug 23905) // if (pCurrentInfo->Update(this, pComponentData) == 0) { pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode); } } }; // switch // now we have to apply the changes in the list of A records if (pCurrentInfo->m_dwErr == 0 && pCurrentInfo->m_action != CDNSRecordNodeEditInfo::none) UpdateARecordsOfNSInfo(pCurrentInfo, pComponentData); } // for return bRes; } // static function void CDNSDomainNode::UpdateARecordsOfNSInfoHelper(CDNSDomainNode* pDomainNode, CDNSRecordNodeEditInfo* pNSInfo, CComponentDataObject* pComponentData, BOOL bAskConfirmation) { ASSERT(pNSInfo->m_dwErr == 0); ASSERT(pNSInfo->m_pRecordNode != NULL); ASSERT(pNSInfo->m_pRecordNode->GetType() == DNS_TYPE_NS); POSITION pos; // get the list of related A records CDNSRecordNodeEditInfoList* pNSInfoList = pNSInfo->m_pEditInfoList; for( pos = pNSInfoList->GetHeadPosition(); pos != NULL; ) { CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos); ASSERT(pCurrentInfo->m_pRecordNode != NULL); ASSERT(pCurrentInfo->m_pRecord != NULL); CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pCurrentInfo->m_pRecordNode; ASSERT(pNSInfo->m_pRecord != NULL); CDNS_NS_Record* pNSRecord = (CDNS_NS_Record*)pNSInfo->m_pRecord; BOOL bHostNameChanged = !_match(pNSRecord->m_szNameNode, pARecordNode); if (bHostNameChanged) { // the NS record points to a different host, so need // to delete the old A RR and create a new one BOOL bRemoveOld = _ConfirmEditAction(pCurrentInfo, bAskConfirmation); CDNSRecordNodeEditInfo::actionType oldAction = pCurrentInfo->m_action; if (pCurrentInfo->m_bExisting && bRemoveOld) { // if the A record was an existing one, need to remove first pCurrentInfo->m_action = CDNSRecordNodeEditInfo::remove; pCurrentInfo->Remove(pDomainNode, pComponentData); } // now decide if have to add if (oldAction == CDNSRecordNodeEditInfo::remove && bRemoveOld) { // it was meant to be removed anyway pCurrentInfo->m_bOwnMemory = TRUE; // edit info will clean up memory } else { // it was meant to be edited or added, restore old action code pCurrentInfo->m_action = oldAction; // change the name of the record pCurrentInfo->m_pRecordNode->SetRecordName(pNSRecord->m_szNameNode, FALSE /*bAtTheNode*/); // add new A record with different FQDN pCurrentInfo->m_action = CDNSRecordNodeEditInfo::add; pCurrentInfo->Update(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures } } else // the name is still the same { switch(pNSInfo->m_action) { case CDNSRecordNodeEditInfo::remove: { // NS record marked for deletion means removing the associated A records if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation)) { pCurrentInfo->Remove(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself } } break; case CDNSRecordNodeEditInfo::add: { if (!pCurrentInfo->m_bExisting) { pCurrentInfo->Update(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures } } break; case CDNSRecordNodeEditInfo::edit: { // NS host name not changed, just update list of A records switch(pCurrentInfo->m_action) { case CDNSRecordNodeEditInfo::remove: { if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation)) { pCurrentInfo->Remove(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself } } break; case CDNSRecordNodeEditInfo::edit: { // we just changed the TTL ASSERT(pCurrentInfo->m_bExisting); pCurrentInfo->Update(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures } break; case CDNSRecordNodeEditInfo::add: { if (!pCurrentInfo->m_bExisting) { pCurrentInfo->Update(pDomainNode, pComponentData); pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures } } break; }; // switch } break; }; // switch } // if,else } // for } void CDNSDomainNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo, CComponentDataObject* pComponentData) { // create a fake domain object to run a query looking for // A records that match the given list of NS records CDNSDummyDomainNode fakeDomain; fakeDomain.SetServerNode(GetServerNode()); fakeDomain.SetZone(GetZoneNode()); BOOL bAskConfirmation = TRUE; // we migth delete A RR's that we need UpdateARecordsOfNSInfoHelper(&fakeDomain, pNSInfo, pComponentData, bAskConfirmation); } void CDNSDomainNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName, CDNSRecordNodeEditInfoList* pNSInfoList) { // just call the static version CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer(); ASSERT(pRootData != NULL); DWORD cAddrCount; PIP_ADDRESS pipAddrs; GetServerNode()->GetListenAddressesInfo(&cAddrCount, &pipAddrs); if (cAddrCount == 0) { // listening on all addresses GetServerNode()->GetServerAddressesInfo(&cAddrCount, &pipAddrs); } FindARecordsFromNSInfo(GetServerNode()->GetRPCName(), GetServerNode()->GetVersion(), cAddrCount, pipAddrs, GetZoneNode()->GetFullName(), lpszNSName, pNSInfoList, pRootData->IsAdvancedView()); } void CDNSDomainNode::FindARecordsFromNSInfo(LPCWSTR lpszServerName, DWORD dwServerVersion, DWORD cServerAddrCount, PIP_ADDRESS pipServerAddrs, LPCWSTR lpszZoneName, LPCWSTR lpszNSName, CDNSRecordNodeEditInfoList* pNSInfoList, BOOL bAdvancedView) { ASSERT(pNSInfoList != NULL); ASSERT(pNSInfoList->IsEmpty()); // specifically look for A records matching a given NS name // set query flags to get all the possible data DWORD dwSelectFlags = DNS_RPC_VIEW_AUTHORITY_DATA | DNS_RPC_VIEW_GLUE_DATA | DNS_RPC_VIEW_ADDITIONAL_DATA; CDNSDomainQueryObj query(lpszServerName, lpszZoneName, dwServerVersion, NULL, // lpszNodeName, no need here lpszNSName, DNS_TYPE_A, dwSelectFlags, FALSE, // zone FALSE, // reverse FALSE, // cache bAdvancedView); query.Enumerate(); // get record from the queue into the info CObjBaseList* pChildList = query.GetQueue(); //int n = pChildList->GetCount(); while (!pChildList->IsEmpty()) { CTreeNode* pNode = dynamic_cast(pChildList->RemoveHead()); ASSERT(pNode != NULL); if (!pNode->IsContainer()) { CDNSRecordNodeBase* pRec = (CDNSRecordNodeBase*)pNode; if (pRec->GetType() == DNS_TYPE_A) { TRACE(_T("Record <%s>\n"), pRec->GetString(2)); pRec->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/); CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo; if (pANodeInfo) { // NOTICE: we assume that all the nodes are glue, so we own the memory pANodeInfo->CreateFromExistingRecord(pRec, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/); pNSInfoList->AddTail(pANodeInfo); } } } else delete pNode; // discard } if (pNSInfoList->GetCount() > 0) return; // got the info we needed just using RPC // Could not find the A records, we need to try DnsQuery to get info outside the server // search using DnsQuery and convert PDNS_RECORD pDnsQueryARecordList = NULL; // if available, use the provided addresses to do a DnsQuery() PIP_ARRAY pipArr = NULL; if ( (cServerAddrCount > 0) && (pipServerAddrs != NULL) ) { pipArr = (PIP_ARRAY)malloc(sizeof(DWORD)+sizeof(IP_ADDRESS)*cServerAddrCount); if (!pipArr) { return; } pipArr->AddrCount = cServerAddrCount; memcpy(pipArr->AddrArray, pipServerAddrs, sizeof(IP_ADDRESS)*cServerAddrCount); } DWORD dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A, DNS_QUERY_NO_RECURSION, pipArr, &pDnsQueryARecordList, NULL); if (pipArr) { free(pipArr); pipArr = 0; } // no luck, try a simple query, with no IP addresses specified if (pDnsQueryARecordList == NULL) { dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A, DNS_QUERY_NO_RECURSION, NULL, &pDnsQueryARecordList, NULL); } if (pDnsQueryARecordList == NULL) return; // failed, no way to resolve IP address PDNS_RECORD pCurrDnsQueryRecord = pDnsQueryARecordList; while (pCurrDnsQueryRecord) { if (pCurrDnsQueryRecord->Flags.S.Section == DNSREC_ANSWER) { if (pCurrDnsQueryRecord->wType == DNS_TYPE_A) { // create a record node CDNSRecordNodeBase* pRecordNode = CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType); pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, 0x0); pRecordNode->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/); CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo; if (pANodeInfo) { pANodeInfo->m_bFromDnsQuery = TRUE; // // NOTICE: we assume that all the nodes are glue, so we own the memory // pANodeInfo->CreateFromExistingRecord(pRecordNode, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/); pNSInfoList->AddTail(pANodeInfo); } } } // goto next record pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext; } DnsRecordListFree(pDnsQueryARecordList, DnsFreeRecordListDeep); } ////////////////////////////////////////////////////////////////////////////////// DNS_STATUS CDNSDomainNode::EnumerateNodes(LPCTSTR lpszServerName, LPCTSTR lpszZoneName, LPCTSTR lpszNodeName, LPCTSTR lpszFullNodeName, WORD wRecordType, DWORD dwSelectFlag, BOOL, BOOL bReverse, BOOL bAdvancedView, CDNSDomainQueryObj* pQuery) { ASSERT(pQuery != NULL); USES_CONVERSION; DNS_STATUS err = 0; CHAR szStartChildAnsi[3*MAX_DNS_NAME_LEN + 1]; // can have multibyte chars, count NULL szStartChildAnsi[0] = NULL; WCHAR szStartChild[MAX_DNS_NAME_LEN + 1]; // count NULL szStartChild[0] = NULL; CTreeNode* pNodeToInsert = NULL; // delayed insert CDNSRecordNodeBase* pMoreDataNode = NULL; // convert to UTF8 names LPCSTR lpszFullNodeNameAnsi = W_TO_UTF8(lpszFullNodeName); LPCSTR lpszZoneNameAnsi = W_TO_UTF8(lpszZoneName); BOOL bTooMuchData = FALSE; do // while more data { // get a chunk of data from RPC call BYTE* pbRpcBuffer = NULL; DWORD cbRpcBufferUsed = 0; err = ::DnssrvEnumRecords(lpszServerName, lpszZoneNameAnsi, lpszFullNodeNameAnsi, // e.g. "foo.bar.com." szStartChildAnsi, // Start Child wRecordType, dwSelectFlag, NULL, // pszFilterStart NULL, // pszFilterStop &cbRpcBufferUsed, &pbRpcBuffer); if ((err != ERROR_MORE_DATA) && (err != 0)) return err; // bail out if there is an error // walk the memory and build objects DNS_RPC_NODE * pDnsNode = (DNS_RPC_NODE *)pbRpcBuffer; DNS_RPC_RECORD * pDnsRecord; void* pvEndOfRpcBuffer = pbRpcBuffer + cbRpcBufferUsed; while ( (!bTooMuchData) && (pDnsNode < pvEndOfRpcBuffer) ) { // get an ANSI null terminated copy memcpy(szStartChildAnsi, pDnsNode->dnsNodeName.achName, pDnsNode->dnsNodeName.cchNameLength); szStartChildAnsi[pDnsNode->dnsNodeName.cchNameLength] = NULL; // // get a UNICODE null terminated copy // if (szStartChildAnsi[0] == NULL) { szStartChild[0] = NULL; } else { DnsUtf8ToWHelper(szStartChild, szStartChildAnsi, pDnsNode->dnsNodeName.cchNameLength+1); } if (pDnsNode->dwChildCount || (pDnsNode->dwFlags & DNS_RPC_NODE_FLAG_STICKY)) { BOOL bDelegation = ( ((dwSelectFlag & DNS_RPC_VIEW_CACHE_DATA) == 0) && ((pDnsNode->dwFlags & DNS_RPC_FLAG_ZONE_ROOT) != 0) ); CDNSDomainNode* p = NULL; if (pQuery->CanAddDomain(szStartChild)) { bTooMuchData = pQuery->TooMuchData(); if (!bTooMuchData) { p = new CDNSDomainNode(bDelegation); p->SetNames(FALSE, bReverse, bAdvancedView, szStartChild, lpszFullNodeName); } } if (pNodeToInsert != NULL) { VERIFY(pQuery->AddQueryResult(pNodeToInsert)); } pNodeToInsert = p; } pDnsRecord = (DNS_RPC_RECORD *)((BYTE *)pDnsNode + NEXT_DWORD(pDnsNode->wLength)); ASSERT(IS_DWORD_ALIGNED(pDnsRecord)); // // Add the records under that node // UINT cRecordCount = pDnsNode->wRecordCount; while ( (!bTooMuchData) && (cRecordCount--) ) { CDNSRecordNodeBase* p = NULL; BOOL bAtTheNode = szStartChild[0] == NULL; LPCWSTR lpszRecordName = (bAtTheNode) ? lpszNodeName : szStartChild; if (pQuery->CanAddRecord(pDnsRecord->wType, lpszRecordName)) { TRACE(_T("\tCan add record %ws\n"), lpszRecordName); bTooMuchData = pQuery->TooMuchData(); if (!bTooMuchData) { if (bAtTheNode) { p = CDNSRecordInfo::CreateRecordNodeFromRPCData( lpszRecordName, pDnsRecord,bAtTheNode); } else { // filter out the NS records that are not at the node if (pDnsRecord->wType != DNS_TYPE_NS) { p = CDNSRecordInfo::CreateRecordNodeFromRPCData( lpszRecordName, pDnsRecord,bAtTheNode); } } } // if not too much data } // if can add if (p != NULL) { p->SetFlagsDown(TN_FLAG_DNS_RECORD_FULL_NAME, !bAdvancedView); if (pNodeToInsert != NULL) { VERIFY(pQuery->AddQueryResult(pNodeToInsert)); } if (pMoreDataNode != NULL) { // // If there was more data check to see if the new node is the same as the // last node from the previous batch. Insert it if they are different, delete // it if they are not // CString szMoreDataName = pMoreDataNode->GetDisplayName(); CString szPName = p->GetDisplayName(); if (szMoreDataName == szPName && pMoreDataNode->GetType() == p->GetType() && _wcsicmp(pMoreDataNode->GetString(3), p->GetString(3)) == 0) { delete pMoreDataNode; } else { VERIFY(pQuery->AddQueryResult(pMoreDataNode)); } pMoreDataNode = NULL; } pNodeToInsert = p; } pDnsRecord = DNS_NEXT_RECORD(pDnsRecord); } // while cRecordCount // The new node is found at the end of the last record pDnsNode = (DNS_RPC_NODE *)pDnsRecord; } // while end of buffer // we still have a node to insert, but we discard it if there is more data // because we are going to get it again and we want to avoid duplication if (pNodeToInsert != NULL) { if (bTooMuchData) { delete pNodeToInsert; } else if (err == ERROR_MORE_DATA) { // // Doesn't matter if this turns out NULL because we only want // pMoreDataNode to be a record node. If its a domain node we // can just ignore it // pMoreDataNode = dynamic_cast(pNodeToInsert); } else { VERIFY(pQuery->AddQueryResult(pNodeToInsert)); } pNodeToInsert = NULL; } ::DnssrvFreeRecordsBuffer(pbRpcBuffer); } while ( !bTooMuchData && (err == ERROR_MORE_DATA) ) ; // we are bailing out because of too much data, // need to let the main tread know if (bTooMuchData && (err != ERROR_MORE_DATA)) { err = ERROR_MORE_DATA; } return err; } DNS_STATUS CDNSDomainNode::Create() { USES_CONVERSION; LPCWSTR lpszFullZoneName = NULL; CDNSZoneNode* pZoneNode = GetZoneNode(); if (pZoneNode != NULL) lpszFullZoneName = pZoneNode->GetFullName(); DNS_STATUS err = ::DnssrvUpdateRecord(GetServerNode()->GetRPCName(), W_TO_UTF8(lpszFullZoneName), W_TO_UTF8(GetFullName()), NULL, NULL); return err; } DNS_STATUS CDNSDomainNode::Delete() { USES_CONVERSION; LPCWSTR lpszFullZoneName = NULL; CDNSZoneNode* pZoneNode = GetZoneNode(); if (pZoneNode != NULL) lpszFullZoneName = pZoneNode->GetFullName(); return ::DnssrvDeleteNode(GetServerNode()->GetRPCName(), W_TO_UTF8(lpszFullZoneName), W_TO_UTF8(GetFullName()), TRUE // fDeleteSubtree ); } ///////////////////////////////////////////////////////////////////////// // CDNSRootHintsNode DNS_STATUS CDNSRootHintsNode::QueryForRootHints(LPCTSTR lpszServerName, DWORD dwServerVersion) { USES_CONVERSION; DWORD dwSelectFlags = DNS_RPC_VIEW_ROOT_HINT_DATA | DNS_RPC_VIEW_ADDITIONAL_DATA | DNS_RPC_VIEW_NO_CHILDREN; CDNSDomainQueryObj query(lpszServerName, UTF8_TO_W(DNS_ZONE_ROOT_HINTS), //lpszZoneName, needs to be "..RootHints" as defined in dnsrpc.h dwServerVersion, GetDisplayName(), m_szFullName, DNS_TYPE_NS, dwSelectFlags, FALSE, // zone FALSE, // reverse FALSE, // cache FALSE); query.Enumerate(); DWORD dwErr = query.GetError(); if (dwErr != 0) return dwErr; // get record from the queue into the folder CObjBaseList* pChildList = query.GetQueue(); //int n = pChildList->GetCount(); while (!pChildList->IsEmpty()) { CTreeNode* pNode = dynamic_cast(pChildList->RemoveHead()); // NOTICE: for NT 4.0 servers, we get bogus container nodes // that we have to suppress if(pNode->IsContainer()) { delete pNode; } else { OnHaveRecord((CDNSRecordNodeBase*)pNode, NULL); // add to the list of NS records AddChildToList(pNode); } } return (DNS_STATUS)dwErr; } void CDNSRootHintsNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName, CDNSRecordNodeEditInfoList* pNSInfoList) { ASSERT(pNSInfoList != NULL); // // for root hints, we have all the records in this folder and we // can edit them // POSITION pos; for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos); ASSERT(!pCurrentChild->IsContainer()); CDNSRecordNodeBase* pRecordNode = (CDNSRecordNodeBase*)pCurrentChild; if (DNS_TYPE_A == pRecordNode->GetType()) { CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pRecordNode; if (_match(lpszNSName, pARecordNode)) { CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo; // // NOTICE: the root hints folder owns the memory // if (pANodeInfo != NULL) { pANodeInfo->CreateFromExistingRecord(pARecordNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/); pNSInfoList->AddTail(pANodeInfo); } else { TRACE(_T("Failed to allocate memory in CDNSRootHintsNode::FindARecordsFromNSInfo")); ASSERT(FALSE); } } } } } void CDNSRootHintsNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo, CComponentDataObject* pComponentData) { BOOL bAskConfirmation = FALSE; // need to edit ALL A records UpdateARecordsOfNSInfoHelper(this, pNSInfo, pComponentData, bAskConfirmation); } DNS_STATUS CDNSRootHintsNode::Clear() { // // clear the list of cached NS record pointers // GetNSRecordNodeList()->RemoveAll(); // // remove all the records from the server // DNS_STATUS err = 0; POSITION pos; for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos); ASSERT(!pCurrentChild->IsContainer()); CDNSRecordNodeBase* pRecordNode = (CDNSRecordNodeBase*)pCurrentChild; DNS_STATUS currErr = pRecordNode->DeleteOnServer(); if (currErr != 0) { // // just ge the last error, if any // err = currErr; } } // // clear the list of children in the folder (we are hidden, so no UI deletions) // RemoveAllChildrenFromList(); return err; } DNS_STATUS CDNSRootHintsNode::InitializeFromDnsQueryData(PDNS_RECORD pRootHintsRecordList) { // need to remove all the previous root hints from the server // let's be sure we get recent data // clear the list of children in the folder (we are hidden, so no UI deletions) RemoveAllChildrenFromList(); // acqure the list of current root hints CDNSServerNode* pServerNode = GetServerNode(); DNS_STATUS dwErr = QueryForRootHints(pServerNode->GetRPCName(), pServerNode->GetVersion()); if (dwErr != 0) { TRACE(_T("Failed to remove old Root Hints, dwErr = %x hex\n"), dwErr); return dwErr; } // remove all the old root hints from server and client side dwErr = Clear(); if (dwErr != 0) { TRACE(_T("Failed to clear Root Hints, dwErr = %x hex\n"), dwErr); return dwErr; } // walk through the list of root hints, // convert to C++ format, // write to server and add to the folder list (no UI, folder hidden) PDNS_RECORD pCurrDnsQueryRecord = pRootHintsRecordList; while (pCurrDnsQueryRecord != NULL) { ASSERT( (pCurrDnsQueryRecord->wType == DNS_TYPE_A) || (pCurrDnsQueryRecord->wType == DNS_TYPE_NS) ); // create a record node and read data from DnsQuery format CDNSRecordNodeBase* pRecordNode = CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType); pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, DNS_RPC_RECORD_FLAG_ZONE_ROOT); // set the record node container pRecordNode->SetContainer(this); // set the record node name BOOL bAtTheNode = (pCurrDnsQueryRecord->wType == DNS_TYPE_NS); pRecordNode->SetRecordName(pCurrDnsQueryRecord->pName, bAtTheNode); // write on server // the default TTL does not apply here DNS_STATUS err = pRecordNode->Update(NULL, FALSE); // NULL = create new, FALSE = use def TTL if (err == 0) VERIFY(AddChildToList(pRecordNode)); else { dwErr = err; // mark las error delete pRecordNode; // something went wrong } pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext; } // force a write on the server, to make sure the cache file is written right away return CDNSZoneNode::WriteToDatabase(pServerNode->GetRPCName(), DNS_ZONE_ROOT_HINTS); }