Windows-Server-2003/admin/snapin/dsadmin/fsmoui.cpp

520 lines
13 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: fsmoui.cpp
//
//--------------------------------------------------------------------------
// File: fsmoui.cpp
#include "stdafx.h"
#include "dsutil.h"
#include "util.h"
#include "uiutil.h"
#include "fsmoui.h"
#include "helpids.h"
#include "dsgetdc.h" //DsEnumerateDomainTrusts
#include "lm.h" //NetApiBufferFree
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////
// CFsmoPropertyPage
BEGIN_MESSAGE_MAP(CFsmoPropertyPage, CPropertyPage)
ON_BN_CLICKED(IDC_CHANGE_FSMO, OnChange)
ON_WM_HELPINFO()
END_MESSAGE_MAP()
CFsmoPropertyPage::CFsmoPropertyPage(CFsmoPropertySheet* pSheet, FSMO_TYPE fsmoType)
{
m_pSheet = pSheet;
m_fsmoType = fsmoType;
// load the caption (tab control text) depending on the FSMO type
UINT nIDCaption = 0;
switch (m_fsmoType)
{
case RID_POOL_FSMO:
nIDCaption = IDS_RID_POOL_FSMO;
break;
case PDC_FSMO:
nIDCaption = IDS_PDC_FSMO;
break;
case INFRASTUCTURE_FSMO:
nIDCaption = IDS_INFRASTRUCTURE_FSMO;
break;
};
Construct(IDD_FSMO_PAGE, nIDCaption);
}
BOOL CFsmoPropertyPage::OnInitDialog()
{
CPropertyPage::OnInitDialog();
//
// We just want a close button since we are not applying any changes
// directly from this page
//
::SendMessage(GetParent()->GetSafeHwnd(), PSM_CANCELTOCLOSE, 0, 0);
// init the status (online/offline) control)
m_fsmoServerState.Init(::GetDlgItem(m_hWnd, IDC_STATIC_FSMO_STATUS));
// set the server we are focused on
SetDlgItemText(IDC_EDIT_CURRENT_DC, m_pSheet->GetBasePathsInfo()->GetServerName());
// set the FSMO description
CString szDesc;
switch (m_fsmoType)
{
case RID_POOL_FSMO:
VERIFY(szDesc.LoadString(IDS_RID_POOL_FSMO_DESC));
break;
case PDC_FSMO:
VERIFY(szDesc.LoadString(IDS_PDC_FSMO_DESC));
break;
case INFRASTUCTURE_FSMO:
VERIFY(szDesc.LoadString(IDS_INFRASTRUCTURE_FSMO_DESC));
break;
};
SetDlgItemText(IDC_STATIC_FSMO_DESC, szDesc);
{ // scope for the wait cursor object
CWaitCursor wait;
// retrieve the FSMO owner
MyBasePathsInfo fsmoOwnerInfo;
PWSTR pszFsmoOwner = 0;
HRESULT hr = FindFsmoOwner(m_pSheet->GetBasePathsInfo(), m_fsmoType, &fsmoOwnerInfo,
&pszFsmoOwner);
if (SUCCEEDED(hr) && pszFsmoOwner)
{
m_szFsmoOwnerServerName = pszFsmoOwner;
delete[] pszFsmoOwner;
pszFsmoOwner = 0;
}
_SetFsmoServerStatus(SUCCEEDED(hr));
}
return TRUE;
}
#ifdef DBG
UINT GetInfoFromIniFileIfDBG(LPCWSTR lpszSection, LPCWSTR lpszKey, INT nDefault = 0)
{
static LPCWSTR lpszFile = L"\\system32\\dsadmin.ini";
WCHAR szFilePath[2*MAX_PATH];
UINT nLen = ::GetSystemWindowsDirectory(szFilePath, 2*MAX_PATH);
if (nLen == 0)
return nDefault;
wcscat(szFilePath, lpszFile);
return ::GetPrivateProfileInt(lpszSection, lpszKey, nDefault, szFilePath);
}
#endif
void CFsmoPropertyPage::OnChange()
{
// Test stuff
/*
{
HRESULT hrTest = E_OUTOFMEMORY;
BOOL bTest = AllowForcedTransfer(hrTest);
return;
}
*/
CThemeContextActivator activator;
// verify we have different servers
if (m_szFsmoOwnerServerName.CompareNoCase(m_pSheet->GetBasePathsInfo()->GetServerName()) == 0)
{
ReportErrorEx(m_hWnd,IDS_WARNING_FSMO_CHANGE_FOCUS,S_OK,
MB_OK | MB_ICONERROR, NULL, 0);
return;
}
bool bConfirm = false; //ask for confirmation only once
if( m_fsmoType == INFRASTUCTURE_FSMO )
{
//check if target DC is GC
//Try to bind to GC port, fails if not GC
IADs *pObject;
HRESULT hr1;
CString strServer = L"GC://";
strServer += m_pSheet->GetBasePathsInfo()->GetServerName();
hr1 = DSAdminOpenObject(strServer,
IID_IADs,
(void**) &pObject,
TRUE /*bServer*/);
if (SUCCEEDED(hr1))
{
//Release Interface, we don't need it
pObject->Release();
//Check if domain has any trusted domains in the forest
// The Infrastructure Master is responsible for ensuring
// referencial integrity in the database (all DN attributes
// actually have an object at the other end). The problem
// with having the Infrastructure Master on a GC is that
// when there are references across domain the object
// actually exists instead of a phantom (placeholder) that the DS inserts
// into the database. Normally the phantom would tell the DS
// to check in the other domain to see if the object has been
// moved or deleted, but since the "real" object is already in
// the database (because its a GC) then the integrity can be
// broken. So we only have to warn the user when transferring to
// a GC if there is the possibility for cross domain references
DS_DOMAIN_TRUSTS *Domains = 0;
DWORD result = 0;
ULONG DomainCount=0;
result = DsEnumerateDomainTrusts (
(LPWSTR)m_pSheet->GetBasePathsInfo()->GetServerName(),
DS_DOMAIN_IN_FOREST,
&Domains,
&DomainCount
);
if( HRESULT_CODE(result) == NO_ERROR )
{
NetApiBufferFree( Domains );
if( DomainCount > 0 )
{
LPTSTR ptzFormat = NULL;
LPTSTR ptzMessage = NULL;
int cch = 0;
INT_PTR retval;
// load message format
if (!LoadStringToTchar(IDS_IFSMO_TARGET_DC_IS_GC, &ptzFormat))
{
ASSERT(FALSE);
}
PVOID apv[2] = {
NULL,
(LPWSTR)m_pSheet->GetBasePathsInfo()->GetServerName()
};
// generate actual message
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
ptzFormat,
NULL,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PTSTR)&ptzMessage, 0, (va_list*)apv);
if (!cch)
{
ASSERT(FALSE);
}
//NTRAID#NTBUG9-572002-2002/03/10-jmessec not handling error if cch == 0 (not critical)
CMoreInfoMessageBox dlg(m_hWnd,
m_pSheet->GetIDisplayHelp(),
TRUE,
true);
dlg.SetMessage(ptzMessage);
dlg.SetURL(DSADMIN_MOREINFO_FSMO_TARGET_DC_IS_GC);
retval = dlg.DoModal();
bConfirm = true;
//clean up
if( NULL != ptzFormat )
{
delete ptzFormat;
}
if( NULL != ptzMessage )
{
LocalFree(ptzMessage);
}
if( retval == IDCANCEL )
{
return;
}
}
}
}
}
// make sure the user wants to do it
if (!bConfirm && ReportErrorEx(m_hWnd,IDS_CHANGE_FSMO_CONFIRMATION,S_OK,
MB_YESNO | MB_ICONWARNING|MB_DEFBUTTON2, NULL, 0) != IDYES)
return;
// try a graceful transfer
HRESULT hr;
{ // scope for the wait cursor object
CWaitCursor wait;
if ( m_fsmoType == PDC_FSMO )
{
hr = CheckpointFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo());
TRACE(_T("back from Checkpoint API, hr is %lx\n"), hr);
if (FAILED(hr))
{
//
// See if we are in native mode or mixed mode
//
BOOL bMixedMode = TRUE;
CString szDomainRoot;
m_pSheet->GetBasePathsInfo()->GetDefaultRootPath(szDomainRoot);
if (!szDomainRoot.IsEmpty())
{
//
// bind to the domain object
//
CComPtr<IADs> spDomainObj;
hr = DSAdminOpenObject(szDomainRoot,
IID_IADs,
(void **) &spDomainObj,
TRUE /*bServer*/);
if (SUCCEEDED(hr))
{
//
// retrieve the mixed node attribute
//
CComVariant Mixed;
CComBSTR bsMixed(L"nTMixedDomain");
spDomainObj->Get(bsMixed, &Mixed);
bMixedMode = (BOOL)Mixed.bVal;
}
}
if (bMixedMode)
{
if (ReportErrorEx(m_hWnd, IDS_CHANGE_FSMO_CHECKPOINT_FAILED, S_OK,
MB_YESNO | MB_ICONWARNING, NULL, 0) != IDYES)
{
return;
}
}
else
{
if (ReportErrorEx(m_hWnd, IDS_CHANGE_FSMO_CHECKPOINT_FAILED_NATIVEMODE, S_OK,
MB_YESNO | MB_ICONWARNING, NULL, 0) != IDYES)
{
return;
}
}
}
}
hr = GracefulFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo(), m_fsmoType);
}
if (FAILED(hr))
{
if (!AllowForcedTransfer(hr))
return;
// try the forced transfer
CWaitCursor wait;
hr = ForcedFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo(), m_fsmoType);
}
if (SUCCEEDED(hr))
{
m_szFsmoOwnerServerName = m_pSheet->GetBasePathsInfo()->GetServerName();
_SetFsmoServerStatus(TRUE);
ReportErrorEx(m_hWnd,IDS_CHANGE_FSMO_SUCCESS,S_OK,
MB_OK, NULL, 0);
}
else
{
ReportErrorEx(m_hWnd, IDS_ERROR_CHANGE_FSMO_OWNER, hr,
MB_OK | MB_ICONERROR, NULL, 0);
}
}
void CFsmoPropertyPage::_SetFsmoServerStatus(BOOL bOnLine)
{
// set the FSMO owner server name
if (m_szFsmoOwnerServerName.IsEmpty())
{
CString szError;
szError.LoadString(IDS_FSMO_SERVER_ERROR);
SetDlgItemText(IDC_EDIT_CURRENT_FSMO_DC, szError);
}
else
{
SetDlgItemText(IDC_EDIT_CURRENT_FSMO_DC, m_szFsmoOwnerServerName);
}
// set the status of the FSMO owner server
m_fsmoServerState.SetToggleState(bOnLine);
}
void CFsmoPropertyPage::OnHelpInfo(HELPINFO * pHelpInfo )
{
TRACE(_T("OnHelpInfo: CtrlId = %d, ContextId = 0x%x\n"),
pHelpInfo->iCtrlId, pHelpInfo->dwContextId);
if (pHelpInfo->iCtrlId < 1) {
return;
}
DWORD_PTR HelpArray = 0;
switch (m_fsmoType)
{
case RID_POOL_FSMO:
HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_RID_FSMO_PAGE;
break;
case PDC_FSMO:
HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_PDC_FSMO_PAGE;
break;
case INFRASTUCTURE_FSMO:
HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_INFRA_FSMO_PAGE;
break;
};
::WinHelp((HWND)pHelpInfo->hItemHandle,
DSADMIN_CONTEXT_HELP_FILE,
HELP_WM_HELP,
HelpArray);
}
void ChangeFormatParamOnString(CString& szFmt)
{
int nPos = szFmt.Find(L"%1");
if (nPos == -1)
return;
szFmt.SetAt(nPos+1, L's');
}
BOOL CFsmoPropertyPage::AllowForcedTransfer(HRESULT hr)
{
CThemeContextActivator activator;
BOOL bAllow = FALSE;
PWSTR pszError = 0;
StringErrorFromHr(hr, &pszError);
// retrieve the DWORD error code
DWORD dwErr = (hr & 0x0000FFFF);
if ( (dwErr != ERROR_ACCESS_DENIED) &&
((m_fsmoType == PDC_FSMO) || (m_fsmoType == INFRASTUCTURE_FSMO)))
{
// allow forced, so ask
CString szFmt, szMsg;
szFmt.LoadString(IDS_CHANGE_FSMO_CONFIRMATION_FORCED);
szMsg.Format(szFmt, pszError);
CMoreInfoMessageBox dlg(m_hWnd, m_pSheet->GetIDisplayHelp(), TRUE, true);
dlg.SetMessage(szMsg);
dlg.SetURL((m_fsmoType == PDC_FSMO) ?
DSADMIN_MOREINFO_PDC_FSMO_TOPIC :
DSADMIN_MOREINFO_INFRASTUCTURE_FSMO_TOPIC);
if (dlg.DoModal() == IDOK)
bAllow = TRUE;
}
else
{
// warn only, no forced transfer option
CString szFmt, szMsg;
szFmt.LoadString(IDS_ERROR_CHANGE_FSMO_OWNER);
// this format string has the replaceable parameter marked as %1
// we need it changed into %s
ChangeFormatParamOnString(szFmt);
szMsg.Format(szFmt, pszError);
CMoreInfoMessageBox dlg(m_hWnd, m_pSheet->GetIDisplayHelp(), FALSE);
dlg.SetMessage(szMsg);
dlg.SetURL(DSADMIN_MOREINFO_RID_POOL_FSMO_TOPIC);
dlg.DoModal();
}
if (pszError)
{
delete[] pszError;
pszError = 0;
}
return bAllow;
}
//////////////////////////////////////////////////////////////////
// CFsmoPropertySheet
int CALLBACK CFsmoPropertySheet::PropSheetCallBack(HWND hwndDlg,
UINT uMsg,
LPARAM)
{
switch (uMsg) {
case PSCB_INITIALIZED:
DWORD dwStyle = GetWindowLong (hwndDlg, GWL_EXSTYLE);
dwStyle |= WS_EX_CONTEXTHELP;
SetWindowLong (hwndDlg, GWL_EXSTYLE, dwStyle);
break;
}
return 0;
}
CFsmoPropertySheet::CFsmoPropertySheet(MyBasePathsInfo* pInfo,
HWND HWndParent,
IDisplayHelp* pIDisplayHelp,
LPCWSTR) :
m_spIDisplayHelp(pIDisplayHelp), m_pInfo(pInfo),
m_page1(this, RID_POOL_FSMO), m_page2(this, PDC_FSMO), m_page3(this, INFRASTUCTURE_FSMO)
{
// build the sheet title
CString szTitle;
szTitle.LoadString(IDS_FSMO_SHEET_TITLE);
// delayed construction
Construct(szTitle, CWnd::FromHandle(HWndParent));
m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_USECALLBACK;
m_psh.pfnCallback = PropSheetCallBack;
AddPage(&m_page1);
AddPage(&m_page2);
AddPage(&m_page3);
}