Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: fsmoui.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // File: fsmoui.cpp
  11. #include "stdafx.h"
  12. #include "dsutil.h"
  13. #include "util.h"
  14. #include "uiutil.h"
  15. #include "fsmoui.h"
  16. #include "helpids.h"
  17. #include "dsgetdc.h" //DsEnumerateDomainTrusts
  18. #include "lm.h" //NetApiBufferFree
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. //////////////////////////////////////////////////////////////////
  25. // CFsmoPropertyPage
  26. BEGIN_MESSAGE_MAP(CFsmoPropertyPage, CPropertyPage)
  27. ON_BN_CLICKED(IDC_CHANGE_FSMO, OnChange)
  28. ON_WM_HELPINFO()
  29. END_MESSAGE_MAP()
  30. CFsmoPropertyPage::CFsmoPropertyPage(CFsmoPropertySheet* pSheet, FSMO_TYPE fsmoType)
  31. {
  32. m_pSheet = pSheet;
  33. m_fsmoType = fsmoType;
  34. // load the caption (tab control text) depending on the FSMO type
  35. UINT nIDCaption = 0;
  36. switch (m_fsmoType)
  37. {
  38. case RID_POOL_FSMO:
  39. nIDCaption = IDS_RID_POOL_FSMO;
  40. break;
  41. case PDC_FSMO:
  42. nIDCaption = IDS_PDC_FSMO;
  43. break;
  44. case INFRASTUCTURE_FSMO:
  45. nIDCaption = IDS_INFRASTRUCTURE_FSMO;
  46. break;
  47. };
  48. Construct(IDD_FSMO_PAGE, nIDCaption);
  49. }
  50. BOOL CFsmoPropertyPage::OnInitDialog()
  51. {
  52. CPropertyPage::OnInitDialog();
  53. //
  54. // We just want a close button since we are not applying any changes
  55. // directly from this page
  56. //
  57. ::SendMessage(GetParent()->GetSafeHwnd(), PSM_CANCELTOCLOSE, 0, 0);
  58. // init the status (online/offline) control)
  59. m_fsmoServerState.Init(::GetDlgItem(m_hWnd, IDC_STATIC_FSMO_STATUS));
  60. // set the server we are focused on
  61. SetDlgItemText(IDC_EDIT_CURRENT_DC, m_pSheet->GetBasePathsInfo()->GetServerName());
  62. // set the FSMO description
  63. CString szDesc;
  64. switch (m_fsmoType)
  65. {
  66. case RID_POOL_FSMO:
  67. VERIFY(szDesc.LoadString(IDS_RID_POOL_FSMO_DESC));
  68. break;
  69. case PDC_FSMO:
  70. VERIFY(szDesc.LoadString(IDS_PDC_FSMO_DESC));
  71. break;
  72. case INFRASTUCTURE_FSMO:
  73. VERIFY(szDesc.LoadString(IDS_INFRASTRUCTURE_FSMO_DESC));
  74. break;
  75. };
  76. SetDlgItemText(IDC_STATIC_FSMO_DESC, szDesc);
  77. { // scope for the wait cursor object
  78. CWaitCursor wait;
  79. // retrieve the FSMO owner
  80. MyBasePathsInfo fsmoOwnerInfo;
  81. PWSTR pszFsmoOwner = 0;
  82. HRESULT hr = FindFsmoOwner(m_pSheet->GetBasePathsInfo(), m_fsmoType, &fsmoOwnerInfo,
  83. &pszFsmoOwner);
  84. if (SUCCEEDED(hr) && pszFsmoOwner)
  85. {
  86. m_szFsmoOwnerServerName = pszFsmoOwner;
  87. delete[] pszFsmoOwner;
  88. pszFsmoOwner = 0;
  89. }
  90. _SetFsmoServerStatus(SUCCEEDED(hr));
  91. }
  92. return TRUE;
  93. }
  94. #ifdef DBG
  95. UINT GetInfoFromIniFileIfDBG(LPCWSTR lpszSection, LPCWSTR lpszKey, INT nDefault = 0)
  96. {
  97. static LPCWSTR lpszFile = L"\\system32\\dsadmin.ini";
  98. WCHAR szFilePath[2*MAX_PATH];
  99. UINT nLen = ::GetSystemWindowsDirectory(szFilePath, 2*MAX_PATH);
  100. if (nLen == 0)
  101. return nDefault;
  102. wcscat(szFilePath, lpszFile);
  103. return ::GetPrivateProfileInt(lpszSection, lpszKey, nDefault, szFilePath);
  104. }
  105. #endif
  106. void CFsmoPropertyPage::OnChange()
  107. {
  108. // Test stuff
  109. /*
  110. {
  111. HRESULT hrTest = E_OUTOFMEMORY;
  112. BOOL bTest = AllowForcedTransfer(hrTest);
  113. return;
  114. }
  115. */
  116. CThemeContextActivator activator;
  117. // verify we have different servers
  118. if (m_szFsmoOwnerServerName.CompareNoCase(m_pSheet->GetBasePathsInfo()->GetServerName()) == 0)
  119. {
  120. ReportErrorEx(m_hWnd,IDS_WARNING_FSMO_CHANGE_FOCUS,S_OK,
  121. MB_OK | MB_ICONERROR, NULL, 0);
  122. return;
  123. }
  124. bool bConfirm = false; //ask for confirmation only once
  125. if( m_fsmoType == INFRASTUCTURE_FSMO )
  126. {
  127. //check if target DC is GC
  128. //Try to bind to GC port, fails if not GC
  129. IADs *pObject;
  130. HRESULT hr1;
  131. CString strServer = L"GC://";
  132. strServer += m_pSheet->GetBasePathsInfo()->GetServerName();
  133. hr1 = DSAdminOpenObject(strServer,
  134. IID_IADs,
  135. (void**) &pObject,
  136. TRUE /*bServer*/);
  137. if (SUCCEEDED(hr1))
  138. {
  139. //Release Interface, we don't need it
  140. pObject->Release();
  141. //Check if domain has any trusted domains in the forest
  142. // The Infrastructure Master is responsible for ensuring
  143. // referencial integrity in the database (all DN attributes
  144. // actually have an object at the other end). The problem
  145. // with having the Infrastructure Master on a GC is that
  146. // when there are references across domain the object
  147. // actually exists instead of a phantom (placeholder) that the DS inserts
  148. // into the database. Normally the phantom would tell the DS
  149. // to check in the other domain to see if the object has been
  150. // moved or deleted, but since the "real" object is already in
  151. // the database (because its a GC) then the integrity can be
  152. // broken. So we only have to warn the user when transferring to
  153. // a GC if there is the possibility for cross domain references
  154. DS_DOMAIN_TRUSTS *Domains = 0;
  155. DWORD result = 0;
  156. ULONG DomainCount=0;
  157. result = DsEnumerateDomainTrusts (
  158. (LPWSTR)m_pSheet->GetBasePathsInfo()->GetServerName(),
  159. DS_DOMAIN_IN_FOREST,
  160. &Domains,
  161. &DomainCount
  162. );
  163. if( HRESULT_CODE(result) == NO_ERROR )
  164. {
  165. NetApiBufferFree( Domains );
  166. if( DomainCount > 0 )
  167. {
  168. LPTSTR ptzFormat = NULL;
  169. LPTSTR ptzMessage = NULL;
  170. int cch = 0;
  171. INT_PTR retval;
  172. // load message format
  173. if (!LoadStringToTchar(IDS_IFSMO_TARGET_DC_IS_GC, &ptzFormat))
  174. {
  175. ASSERT(FALSE);
  176. }
  177. PVOID apv[2] = {
  178. NULL,
  179. (LPWSTR)m_pSheet->GetBasePathsInfo()->GetServerName()
  180. };
  181. // generate actual message
  182. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  183. | FORMAT_MESSAGE_FROM_STRING
  184. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  185. ptzFormat,
  186. NULL,
  187. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  188. (PTSTR)&ptzMessage, 0, (va_list*)apv);
  189. if (!cch)
  190. {
  191. ASSERT(FALSE);
  192. }
  193. //NTRAID#NTBUG9-572002-2002/03/10-jmessec not handling error if cch == 0 (not critical)
  194. CMoreInfoMessageBox dlg(m_hWnd,
  195. m_pSheet->GetIDisplayHelp(),
  196. TRUE,
  197. true);
  198. dlg.SetMessage(ptzMessage);
  199. dlg.SetURL(DSADMIN_MOREINFO_FSMO_TARGET_DC_IS_GC);
  200. retval = dlg.DoModal();
  201. bConfirm = true;
  202. //clean up
  203. if( NULL != ptzFormat )
  204. {
  205. delete ptzFormat;
  206. }
  207. if( NULL != ptzMessage )
  208. {
  209. LocalFree(ptzMessage);
  210. }
  211. if( retval == IDCANCEL )
  212. {
  213. return;
  214. }
  215. }
  216. }
  217. }
  218. }
  219. // make sure the user wants to do it
  220. if (!bConfirm && ReportErrorEx(m_hWnd,IDS_CHANGE_FSMO_CONFIRMATION,S_OK,
  221. MB_YESNO | MB_ICONWARNING|MB_DEFBUTTON2, NULL, 0) != IDYES)
  222. return;
  223. // try a graceful transfer
  224. HRESULT hr;
  225. { // scope for the wait cursor object
  226. CWaitCursor wait;
  227. if ( m_fsmoType == PDC_FSMO )
  228. {
  229. hr = CheckpointFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo());
  230. TRACE(_T("back from Checkpoint API, hr is %lx\n"), hr);
  231. if (FAILED(hr))
  232. {
  233. //
  234. // See if we are in native mode or mixed mode
  235. //
  236. BOOL bMixedMode = TRUE;
  237. CString szDomainRoot;
  238. m_pSheet->GetBasePathsInfo()->GetDefaultRootPath(szDomainRoot);
  239. if (!szDomainRoot.IsEmpty())
  240. {
  241. //
  242. // bind to the domain object
  243. //
  244. CComPtr<IADs> spDomainObj;
  245. hr = DSAdminOpenObject(szDomainRoot,
  246. IID_IADs,
  247. (void **) &spDomainObj,
  248. TRUE /*bServer*/);
  249. if (SUCCEEDED(hr))
  250. {
  251. //
  252. // retrieve the mixed node attribute
  253. //
  254. CComVariant Mixed;
  255. CComBSTR bsMixed(L"nTMixedDomain");
  256. spDomainObj->Get(bsMixed, &Mixed);
  257. bMixedMode = (BOOL)Mixed.bVal;
  258. }
  259. }
  260. if (bMixedMode)
  261. {
  262. if (ReportErrorEx(m_hWnd, IDS_CHANGE_FSMO_CHECKPOINT_FAILED, S_OK,
  263. MB_YESNO | MB_ICONWARNING, NULL, 0) != IDYES)
  264. {
  265. return;
  266. }
  267. }
  268. else
  269. {
  270. if (ReportErrorEx(m_hWnd, IDS_CHANGE_FSMO_CHECKPOINT_FAILED_NATIVEMODE, S_OK,
  271. MB_YESNO | MB_ICONWARNING, NULL, 0) != IDYES)
  272. {
  273. return;
  274. }
  275. }
  276. }
  277. }
  278. hr = GracefulFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo(), m_fsmoType);
  279. }
  280. if (FAILED(hr))
  281. {
  282. if (!AllowForcedTransfer(hr))
  283. return;
  284. // try the forced transfer
  285. CWaitCursor wait;
  286. hr = ForcedFsmoOwnerTransfer(m_pSheet->GetBasePathsInfo(), m_fsmoType);
  287. }
  288. if (SUCCEEDED(hr))
  289. {
  290. m_szFsmoOwnerServerName = m_pSheet->GetBasePathsInfo()->GetServerName();
  291. _SetFsmoServerStatus(TRUE);
  292. ReportErrorEx(m_hWnd,IDS_CHANGE_FSMO_SUCCESS,S_OK,
  293. MB_OK, NULL, 0);
  294. }
  295. else
  296. {
  297. ReportErrorEx(m_hWnd, IDS_ERROR_CHANGE_FSMO_OWNER, hr,
  298. MB_OK | MB_ICONERROR, NULL, 0);
  299. }
  300. }
  301. void CFsmoPropertyPage::_SetFsmoServerStatus(BOOL bOnLine)
  302. {
  303. // set the FSMO owner server name
  304. if (m_szFsmoOwnerServerName.IsEmpty())
  305. {
  306. CString szError;
  307. szError.LoadString(IDS_FSMO_SERVER_ERROR);
  308. SetDlgItemText(IDC_EDIT_CURRENT_FSMO_DC, szError);
  309. }
  310. else
  311. {
  312. SetDlgItemText(IDC_EDIT_CURRENT_FSMO_DC, m_szFsmoOwnerServerName);
  313. }
  314. // set the status of the FSMO owner server
  315. m_fsmoServerState.SetToggleState(bOnLine);
  316. }
  317. void CFsmoPropertyPage::OnHelpInfo(HELPINFO * pHelpInfo )
  318. {
  319. TRACE(_T("OnHelpInfo: CtrlId = %d, ContextId = 0x%x\n"),
  320. pHelpInfo->iCtrlId, pHelpInfo->dwContextId);
  321. if (pHelpInfo->iCtrlId < 1) {
  322. return;
  323. }
  324. DWORD_PTR HelpArray = 0;
  325. switch (m_fsmoType)
  326. {
  327. case RID_POOL_FSMO:
  328. HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_RID_FSMO_PAGE;
  329. break;
  330. case PDC_FSMO:
  331. HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_PDC_FSMO_PAGE;
  332. break;
  333. case INFRASTUCTURE_FSMO:
  334. HelpArray = (DWORD_PTR)g_aHelpIDs_IDD_INFRA_FSMO_PAGE;
  335. break;
  336. };
  337. ::WinHelp((HWND)pHelpInfo->hItemHandle,
  338. DSADMIN_CONTEXT_HELP_FILE,
  339. HELP_WM_HELP,
  340. HelpArray);
  341. }
  342. void ChangeFormatParamOnString(CString& szFmt)
  343. {
  344. int nPos = szFmt.Find(L"%1");
  345. if (nPos == -1)
  346. return;
  347. szFmt.SetAt(nPos+1, L's');
  348. }
  349. BOOL CFsmoPropertyPage::AllowForcedTransfer(HRESULT hr)
  350. {
  351. CThemeContextActivator activator;
  352. BOOL bAllow = FALSE;
  353. PWSTR pszError = 0;
  354. StringErrorFromHr(hr, &pszError);
  355. // retrieve the DWORD error code
  356. DWORD dwErr = (hr & 0x0000FFFF);
  357. if ( (dwErr != ERROR_ACCESS_DENIED) &&
  358. ((m_fsmoType == PDC_FSMO) || (m_fsmoType == INFRASTUCTURE_FSMO)))
  359. {
  360. // allow forced, so ask
  361. CString szFmt, szMsg;
  362. szFmt.LoadString(IDS_CHANGE_FSMO_CONFIRMATION_FORCED);
  363. szMsg.Format(szFmt, pszError);
  364. CMoreInfoMessageBox dlg(m_hWnd, m_pSheet->GetIDisplayHelp(), TRUE, true);
  365. dlg.SetMessage(szMsg);
  366. dlg.SetURL((m_fsmoType == PDC_FSMO) ?
  367. DSADMIN_MOREINFO_PDC_FSMO_TOPIC :
  368. DSADMIN_MOREINFO_INFRASTUCTURE_FSMO_TOPIC);
  369. if (dlg.DoModal() == IDOK)
  370. bAllow = TRUE;
  371. }
  372. else
  373. {
  374. // warn only, no forced transfer option
  375. CString szFmt, szMsg;
  376. szFmt.LoadString(IDS_ERROR_CHANGE_FSMO_OWNER);
  377. // this format string has the replaceable parameter marked as %1
  378. // we need it changed into %s
  379. ChangeFormatParamOnString(szFmt);
  380. szMsg.Format(szFmt, pszError);
  381. CMoreInfoMessageBox dlg(m_hWnd, m_pSheet->GetIDisplayHelp(), FALSE);
  382. dlg.SetMessage(szMsg);
  383. dlg.SetURL(DSADMIN_MOREINFO_RID_POOL_FSMO_TOPIC);
  384. dlg.DoModal();
  385. }
  386. if (pszError)
  387. {
  388. delete[] pszError;
  389. pszError = 0;
  390. }
  391. return bAllow;
  392. }
  393. //////////////////////////////////////////////////////////////////
  394. // CFsmoPropertySheet
  395. int CALLBACK CFsmoPropertySheet::PropSheetCallBack(HWND hwndDlg,
  396. UINT uMsg,
  397. LPARAM)
  398. {
  399. switch (uMsg) {
  400. case PSCB_INITIALIZED:
  401. DWORD dwStyle = GetWindowLong (hwndDlg, GWL_EXSTYLE);
  402. dwStyle |= WS_EX_CONTEXTHELP;
  403. SetWindowLong (hwndDlg, GWL_EXSTYLE, dwStyle);
  404. break;
  405. }
  406. return 0;
  407. }
  408. CFsmoPropertySheet::CFsmoPropertySheet(MyBasePathsInfo* pInfo,
  409. HWND HWndParent,
  410. IDisplayHelp* pIDisplayHelp,
  411. LPCWSTR) :
  412. m_spIDisplayHelp(pIDisplayHelp), m_pInfo(pInfo),
  413. m_page1(this, RID_POOL_FSMO), m_page2(this, PDC_FSMO), m_page3(this, INFRASTUCTURE_FSMO)
  414. {
  415. // build the sheet title
  416. CString szTitle;
  417. szTitle.LoadString(IDS_FSMO_SHEET_TITLE);
  418. // delayed construction
  419. Construct(szTitle, CWnd::FromHandle(HWndParent));
  420. m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_USECALLBACK;
  421. m_psh.pfnCallback = PropSheetCallBack;
  422. AddPage(&m_page1);
  423. AddPage(&m_page2);
  424. AddPage(&m_page3);
  425. }