520 lines
13 KiB
C++
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);
|
|
}
|
|
|