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.

3067 lines
89 KiB

  1. /*++
  2. Module Name:
  3. RepSet.cpp
  4. --*/
  5. #include "stdafx.h"
  6. #include "DfsCore.h"
  7. #include "RepSet.h"
  8. #include "netutils.h"
  9. #include "ldaputils.h"
  10. #include <dsgetdc.h> // DsGetSiteName
  11. // sort member list based on m_bstrSite
  12. struct FrsMemberCompare : greater<CFrsMember*>
  13. {
  14. bool operator()(const CFrsMember *pMem1, const CFrsMember *pMem2) const
  15. { return (lstrcmpi(pMem1->m_bstrSite, pMem2->m_bstrSite) > 0); }
  16. };
  17. //
  18. // retrieve Site
  19. //
  20. HRESULT GetSiteName(IN BSTR i_bstrServer, OUT BSTR* o_pbstrSite)
  21. {
  22. HRESULT hr = S_OK;
  23. LPTSTR lpszSiteName = NULL;
  24. DWORD dwErr = DsGetSiteName(i_bstrServer, &lpszSiteName);
  25. if (NO_ERROR == dwErr)
  26. {
  27. *o_pbstrSite = SysAllocString(lpszSiteName);
  28. NetApiBufferFree((LPBYTE)lpszSiteName);
  29. if (!*o_pbstrSite)
  30. hr = E_OUTOFMEMORY;
  31. } else if (ERROR_NO_SITENAME == dwErr)
  32. {
  33. *o_pbstrSite = SysAllocString(_T(""));
  34. if (!*o_pbstrSite)
  35. hr = E_OUTOFMEMORY;
  36. } else
  37. {
  38. CComBSTR bstrText;
  39. FormatMessageString(&bstrText, 0, IDS_UNKNOWN_SITE, dwErr);
  40. *o_pbstrSite = bstrText.Copy();
  41. if (!*o_pbstrSite)
  42. hr = E_OUTOFMEMORY;
  43. // hr = HRESULT_FROM_WIN32(dwErr);
  44. }
  45. return hr;
  46. }
  47. /////////////////////////////////////////////////////////////////////////////////////////////////
  48. // constructor
  49. CReplicaSet::CReplicaSet() :
  50. m_pldap(NULL),
  51. m_bNewSchema(FALSE)
  52. {
  53. dfsDebugOut((_T("CReplicaSet::CReplicaSet this=%p\n"), this));
  54. }
  55. /////////////////////////////////////////////////////////////////////////////////////////////////
  56. // destructor
  57. CReplicaSet::~CReplicaSet()
  58. {
  59. _FreeMemberVariables();
  60. dfsDebugOut((_T("CReplicaSet::~CReplicaSet this=%p\n"), this));
  61. }
  62. /////////////////////////////////////////////////////////////////////////////////////////////////
  63. // various properties
  64. STDMETHODIMP CReplicaSet::get_Type(BSTR *pVal)
  65. {
  66. RETURN_INVALIDARG_IF_NULL(pVal);
  67. if (!m_bstrType)
  68. {
  69. m_bstrType = FRS_RSTYPE_OTHER;
  70. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrType);
  71. }
  72. *pVal = m_bstrType.Copy ();
  73. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  74. return S_OK;
  75. }
  76. STDMETHODIMP CReplicaSet::put_Type(BSTR newVal)
  77. {
  78. if (newVal && (BSTR)m_bstrType && !lstrcmpi(newVal, m_bstrType))
  79. return S_OK; // no change
  80. CComBSTR bstrType = ((newVal && *newVal)? newVal : FRS_RSTYPE_DFS);
  81. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrType);
  82. LDAP_ATTR_VALUE pAttrVals[1];
  83. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_TYPE;
  84. pAttrVals[0].vpValue = (void *)(BSTR)bstrType;
  85. pAttrVals[0].bBerValue = false;
  86. HRESULT hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  87. if (SUCCEEDED(hr))
  88. m_bstrType = bstrType;
  89. return hr;
  90. }
  91. STDMETHODIMP CReplicaSet::get_TopologyPref(BSTR* pVal)
  92. {
  93. RETURN_INVALIDARG_IF_NULL(pVal);
  94. if (!m_bstrTopologyPref)
  95. {
  96. m_bstrTopologyPref = FRS_RSTOPOLOGYPREF_CUSTOM;
  97. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrTopologyPref);
  98. }
  99. *pVal = m_bstrTopologyPref.Copy ();
  100. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  101. dfsDebugOut((_T("get_TopologyPref = %s\n"), m_bstrTopologyPref));
  102. return S_OK;
  103. }
  104. STDMETHODIMP CReplicaSet::put_TopologyPref(BSTR newVal)
  105. {
  106. if (newVal && (BSTR)m_bstrTopologyPref && !lstrcmpi(newVal, m_bstrTopologyPref))
  107. return S_OK; // no change
  108. CComBSTR bstrTopologyPref = ((newVal && *newVal)? newVal : FRS_RSTOPOLOGYPREF_CUSTOM);
  109. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrTopologyPref);
  110. HRESULT hr = S_OK;
  111. if (m_bNewSchema)
  112. {
  113. LDAP_ATTR_VALUE pAttrVals[1];
  114. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_TOPOLOGYPREF;
  115. pAttrVals[0].vpValue = (void *)(BSTR)bstrTopologyPref;
  116. pAttrVals[0].bBerValue = false;
  117. hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  118. if (SUCCEEDED(hr))
  119. m_bstrTopologyPref = bstrTopologyPref;
  120. } else
  121. {
  122. m_bstrTopologyPref = bstrTopologyPref;
  123. }
  124. dfsDebugOut((_T("put_TopologyPref = %s\n"), m_bstrTopologyPref));
  125. return hr;
  126. }
  127. STDMETHODIMP CReplicaSet::get_HubMemberDN(BSTR* pVal)
  128. {
  129. RETURN_INVALIDARG_IF_NULL(pVal);
  130. if (!m_bstrHubMemberDN)
  131. {
  132. m_bstrHubMemberDN = _T("");
  133. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrHubMemberDN);
  134. }
  135. *pVal = m_bstrHubMemberDN.Copy ();
  136. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  137. dfsDebugOut((_T("get_HubMemberDN = %s\n"), m_bstrHubMemberDN));
  138. return S_OK;
  139. }
  140. STDMETHODIMP CReplicaSet::put_HubMemberDN(BSTR newVal)
  141. {
  142. if (newVal && (BSTR)m_bstrHubMemberDN && !lstrcmpi(newVal, m_bstrHubMemberDN))
  143. return S_OK; // no change
  144. CComBSTR bstrHubMemberDN = ((newVal && *newVal) ? newVal : _T(""));
  145. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrHubMemberDN);
  146. HRESULT hr = S_OK;
  147. if (m_bNewSchema)
  148. {
  149. LDAP_ATTR_VALUE pAttrVals[1];
  150. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_HUBSERVER;
  151. pAttrVals[0].bBerValue = false;
  152. if (newVal && *newVal)
  153. {
  154. pAttrVals[0].vpValue = (void *)(BSTR)bstrHubMemberDN;
  155. hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  156. } else
  157. {
  158. pAttrVals[0].vpValue = NULL;
  159. hr = ::DeleteValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  160. }
  161. if (SUCCEEDED(hr))
  162. m_bstrHubMemberDN = bstrHubMemberDN;
  163. } else
  164. {
  165. m_bstrHubMemberDN = bstrHubMemberDN;
  166. }
  167. dfsDebugOut((_T("put_HubMemberDN = %s\n"), m_bstrHubMemberDN));
  168. return hr;
  169. }
  170. STDMETHODIMP CReplicaSet::get_PrimaryMemberDN(BSTR* pVal)
  171. {
  172. RETURN_INVALIDARG_IF_NULL(pVal);
  173. if (!m_bstrPrimaryMemberDN)
  174. {
  175. m_bstrPrimaryMemberDN = _T("");
  176. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrPrimaryMemberDN);
  177. }
  178. *pVal = m_bstrPrimaryMemberDN.Copy ();
  179. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  180. return S_OK;
  181. }
  182. STDMETHODIMP CReplicaSet::put_PrimaryMemberDN(BSTR newVal)
  183. {
  184. if (newVal && (BSTR)m_bstrPrimaryMemberDN && !lstrcmpi(newVal, m_bstrPrimaryMemberDN))
  185. return S_OK; // no change
  186. CComBSTR bstrPrimaryMemberDN = ((newVal && *newVal)? newVal : _T(""));
  187. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrPrimaryMemberDN);
  188. LDAP_ATTR_VALUE pAttrVals[1];
  189. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_PRIMARYMEMBER;
  190. pAttrVals[0].bBerValue = false;
  191. HRESULT hr = S_OK;
  192. if (newVal && *newVal)
  193. {
  194. pAttrVals[0].vpValue = (void *)(BSTR)bstrPrimaryMemberDN;
  195. hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  196. } else
  197. {
  198. pAttrVals[0].vpValue = NULL;
  199. hr = ::DeleteValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  200. }
  201. if (SUCCEEDED(hr))
  202. m_bstrPrimaryMemberDN = bstrPrimaryMemberDN;
  203. return hr;
  204. }
  205. STDMETHODIMP CReplicaSet::get_FileFilter(BSTR* pVal)
  206. {
  207. RETURN_INVALIDARG_IF_NULL(pVal);
  208. if (!m_bstrFileFilter)
  209. {
  210. m_bstrFileFilter = _T("");
  211. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFileFilter);
  212. }
  213. *pVal = m_bstrFileFilter.Copy ();
  214. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  215. return S_OK;
  216. }
  217. STDMETHODIMP CReplicaSet::put_FileFilter(BSTR newVal)
  218. {
  219. if (newVal && (BSTR)m_bstrFileFilter && !lstrcmpi(newVal, m_bstrFileFilter))
  220. return S_OK; // no change
  221. CComBSTR bstrFileFilter = ((newVal && *newVal) ? newVal : _T(""));
  222. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFileFilter);
  223. LDAP_ATTR_VALUE pAttrVals[1];
  224. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_FILEFILTER;
  225. pAttrVals[0].bBerValue = false;
  226. HRESULT hr = S_OK;
  227. if (newVal && *newVal)
  228. {
  229. pAttrVals[0].vpValue = (void *)(BSTR)bstrFileFilter;
  230. hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  231. } else
  232. {
  233. pAttrVals[0].vpValue = NULL;
  234. hr = ::DeleteValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  235. }
  236. if (SUCCEEDED(hr))
  237. m_bstrFileFilter = bstrFileFilter;
  238. return hr;
  239. }
  240. STDMETHODIMP CReplicaSet::get_DirFilter(BSTR* pVal)
  241. {
  242. RETURN_INVALIDARG_IF_NULL(pVal);
  243. if (!m_bstrDirFilter)
  244. {
  245. m_bstrDirFilter = _T("");
  246. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDirFilter);
  247. }
  248. *pVal = m_bstrDirFilter.Copy ();
  249. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  250. return S_OK;
  251. }
  252. STDMETHODIMP CReplicaSet::put_DirFilter(BSTR newVal)
  253. {
  254. if (newVal && (BSTR)m_bstrDirFilter && !lstrcmpi(newVal, m_bstrDirFilter))
  255. return S_OK; // no change
  256. CComBSTR bstrDirFilter = ((newVal && *newVal)? newVal : _T(""));
  257. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrDirFilter);
  258. LDAP_ATTR_VALUE pAttrVals[1];
  259. pAttrVals[0].bstrAttribute = ATTR_FRS_REPSET_DIRFILTER;
  260. pAttrVals[0].bBerValue = false;
  261. HRESULT hr = S_OK;
  262. if (newVal && *newVal)
  263. {
  264. pAttrVals[0].vpValue = (void *)(BSTR)bstrDirFilter;
  265. hr = ::ModifyValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  266. } else
  267. {
  268. pAttrVals[0].vpValue = NULL;
  269. hr = ::DeleteValues(m_pldap, m_bstrReplicaSetDN, 1, pAttrVals);
  270. }
  271. if (SUCCEEDED(hr))
  272. m_bstrDirFilter = bstrDirFilter;
  273. return hr;
  274. }
  275. STDMETHODIMP CReplicaSet::get_DfsEntryPath(BSTR* pVal)
  276. {
  277. RETURN_INVALIDARG_IF_NULL(pVal);
  278. if (!m_bstrDfsEntryPath)
  279. {
  280. m_bstrDfsEntryPath = _T("");
  281. RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDfsEntryPath);
  282. }
  283. *pVal = m_bstrDfsEntryPath.Copy ();
  284. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  285. return S_OK;
  286. }
  287. STDMETHODIMP CReplicaSet::get_Domain(BSTR* pVal)
  288. {
  289. RETURN_INVALIDARG_IF_NULL(pVal);
  290. RETURN_INVALIDARG_IF_NULL((BSTR)m_bstrDomain);
  291. *pVal = m_bstrDomain.Copy ();
  292. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  293. return S_OK;
  294. }
  295. STDMETHODIMP CReplicaSet::get_ReplicaSetDN(BSTR* pVal)
  296. {
  297. RETURN_INVALIDARG_IF_NULL(pVal);
  298. RETURN_INVALIDARG_IF_NULL((BSTR)m_bstrReplicaSetDN);
  299. *pVal = m_bstrReplicaSetDN.Copy ();
  300. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  301. return S_OK;
  302. }
  303. STDMETHODIMP CReplicaSet::get_NumOfMembers(long* pVal)
  304. {
  305. RETURN_INVALIDARG_IF_NULL(pVal);
  306. *pVal = m_frsMemberList.size();
  307. return S_OK;
  308. }
  309. STDMETHODIMP CReplicaSet::get_NumOfConnections(long* pVal)
  310. {
  311. RETURN_INVALIDARG_IF_NULL(pVal);
  312. *pVal = m_frsConnectionList.size();
  313. return S_OK;
  314. }
  315. STDMETHODIMP CReplicaSet::get_TargetedDC(BSTR* pVal)
  316. {
  317. RETURN_INVALIDARG_IF_NULL(pVal);
  318. RETURN_INVALIDARG_IF_NULL((BSTR)m_bstrDC);
  319. *pVal = m_bstrDC.Copy ();
  320. RETURN_OUTOFMEMORY_IF_NULL(*pVal);
  321. return S_OK;
  322. }
  323. /////////////////////////////////////////////////////////////////////////////////////////////////
  324. // various methods
  325. STDMETHODIMP CReplicaSet::Create(
  326. BSTR i_bstrDomain,
  327. BSTR i_bstrReplicaSetDN,
  328. BSTR i_bstrType,
  329. BSTR i_bstrTopologyPref,
  330. BSTR i_bstrHubMemberDN,
  331. BSTR i_bstrPrimaryMemberDN,
  332. BSTR i_bstrFileFilter,
  333. BSTR i_bstrDirFilter
  334. )
  335. {
  336. RETURN_INVALIDARG_IF_NULL(i_bstrDomain);
  337. RETURN_INVALIDARG_IF_NULL(i_bstrReplicaSetDN);
  338. RETURN_INVALIDARG_IF_NULL(i_bstrType);
  339. _FreeMemberVariables();
  340. HRESULT hr = S_OK;
  341. do {
  342. m_bstrDomain = i_bstrDomain;
  343. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDomain, &hr);
  344. CComBSTR bstrDomainDN;
  345. hr = GetDomainInfo(
  346. i_bstrDomain,
  347. NULL, // return DC's Dns name
  348. NULL, // return Domain's Dns name
  349. &bstrDomainDN, // return DC=nttest,DC=micr
  350. NULL, // return LDAP://<DC>/<Doma
  351. &m_bstrDomainGuid // return Domain's guid
  352. );
  353. BREAK_IF_FAILED(hr);
  354. hr = ConnectToDS(m_bstrDomain, &m_pldap, &m_bstrDC);
  355. BREAK_IF_FAILED(hr);
  356. //
  357. // get schema version
  358. //
  359. hr = GetSchemaVersionEx(m_bstrDomain, FALSE);
  360. BREAK_IF_FAILED(hr);
  361. m_bNewSchema = (S_OK == hr);
  362. dfsDebugOut((_T("NewSchema=%d\n"), m_bNewSchema));
  363. m_bstrReplicaSetDN = i_bstrReplicaSetDN;
  364. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  365. m_bstrReplicaSetDN += _T(",");
  366. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  367. m_bstrReplicaSetDN += bstrDomainDN;
  368. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  369. m_bstrType = i_bstrType;
  370. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrType, &hr);
  371. //
  372. // create container objects if not exist
  373. //
  374. hr = CreateNtfrsSettingsObjects(m_pldap, m_bstrReplicaSetDN);
  375. BREAK_IF_FAILED(hr);
  376. //
  377. // create this nTFRSReplicaSet object
  378. //
  379. LDAP_ATTR_VALUE pAttrVals[7];
  380. int i = 0;
  381. pAttrVals[i].bstrAttribute = OBJCLASS_ATTRIBUTENAME;
  382. pAttrVals[i].vpValue = (void *)OBJCLASS_NTFRSREPLICASET;
  383. pAttrVals[i].bBerValue = false;
  384. i++;
  385. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_TYPE;
  386. pAttrVals[i].vpValue = (void *)i_bstrType;
  387. pAttrVals[i].bBerValue = false;
  388. if (i_bstrTopologyPref && *i_bstrTopologyPref)
  389. {
  390. m_bstrTopologyPref = i_bstrTopologyPref;
  391. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrTopologyPref, &hr);
  392. if (m_bNewSchema)
  393. {
  394. i++;
  395. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_TOPOLOGYPREF;
  396. pAttrVals[i].vpValue = (void *)i_bstrTopologyPref;
  397. pAttrVals[i].bBerValue = false;
  398. }
  399. if (!lstrcmpi(FRS_RSTOPOLOGYPREF_HUBSPOKE, m_bstrTopologyPref))
  400. {
  401. if (i_bstrHubMemberDN && *i_bstrHubMemberDN)
  402. {
  403. m_bstrHubMemberDN = i_bstrHubMemberDN;
  404. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrHubMemberDN, &hr);
  405. if (m_bNewSchema)
  406. {
  407. i++;
  408. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_HUBSERVER;
  409. pAttrVals[i].vpValue = (void *)i_bstrHubMemberDN;
  410. pAttrVals[i].bBerValue = false;
  411. }
  412. }
  413. }
  414. }
  415. if (i_bstrPrimaryMemberDN && *i_bstrPrimaryMemberDN)
  416. {
  417. m_bstrPrimaryMemberDN = i_bstrPrimaryMemberDN;
  418. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrPrimaryMemberDN, &hr);
  419. i++;
  420. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_PRIMARYMEMBER;
  421. pAttrVals[i].vpValue = (void *)i_bstrPrimaryMemberDN;
  422. pAttrVals[i].bBerValue = false;
  423. }
  424. if (i_bstrFileFilter && *i_bstrFileFilter)
  425. {
  426. m_bstrFileFilter = i_bstrFileFilter;
  427. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFileFilter, &hr);
  428. i++;
  429. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_FILEFILTER;
  430. pAttrVals[i].vpValue = (void *)i_bstrFileFilter;
  431. pAttrVals[i].bBerValue = false;
  432. }
  433. if (i_bstrDirFilter && *i_bstrDirFilter)
  434. {
  435. m_bstrDirFilter = i_bstrDirFilter;
  436. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDirFilter, &hr);
  437. i++;
  438. pAttrVals[i].bstrAttribute = ATTR_FRS_REPSET_DIRFILTER;
  439. pAttrVals[i].vpValue = (void *)i_bstrDirFilter;
  440. pAttrVals[i].bBerValue = false;
  441. }
  442. hr = AddValues(
  443. m_pldap,
  444. m_bstrReplicaSetDN,
  445. ++i,
  446. pAttrVals
  447. );
  448. BREAK_IF_FAILED(hr);
  449. } while (0);
  450. if (FAILED(hr))
  451. {
  452. _FreeMemberVariables();
  453. //
  454. // try to clean empty container objects
  455. //
  456. (void)DeleteNtfrsReplicaSetObjectAndContainers(m_pldap, m_bstrReplicaSetDN);
  457. }
  458. return hr;
  459. }
  460. STDMETHODIMP CReplicaSet::Initialize(BSTR i_bstrDomain, BSTR i_bstrReplicaSetDN)
  461. {
  462. RETURN_INVALIDARG_IF_NULL(i_bstrDomain);
  463. RETURN_INVALIDARG_IF_NULL(i_bstrReplicaSetDN);
  464. _FreeMemberVariables();
  465. HRESULT hr = S_OK;
  466. do {
  467. m_bstrDomain = i_bstrDomain;
  468. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDomain, &hr);
  469. CComBSTR bstrDomainDN;
  470. hr = GetDomainInfo(
  471. i_bstrDomain,
  472. NULL, // return DC's Dns name
  473. NULL, // return Domain's Dns name
  474. &bstrDomainDN, // return DC=nttest,DC=micr
  475. NULL, // return LDAP://<DC>/<Doma
  476. &m_bstrDomainGuid // return Domain's guid
  477. );
  478. BREAK_IF_FAILED(hr);
  479. m_bstrReplicaSetDN = i_bstrReplicaSetDN;
  480. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  481. hr = ConnectToDS(m_bstrDomain, &m_pldap, &m_bstrDC);
  482. BREAK_IF_FAILED(hr);
  483. //
  484. // get schema version
  485. //
  486. hr = GetSchemaVersionEx(m_bstrDomain, FALSE);
  487. BREAK_IF_FAILED(hr);
  488. m_bNewSchema = (S_OK == hr);
  489. dfsDebugOut((_T("NewSchema=%d\n"), m_bNewSchema));
  490. m_bstrReplicaSetDN += _T(",");
  491. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  492. m_bstrReplicaSetDN += bstrDomainDN;
  493. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
  494. PLDAP_ATTR_VALUE pValues[7] = {0,0,0,0,0,0,0};
  495. LDAP_ATTR_VALUE pAttributes[6];
  496. int i = 0;
  497. pAttributes[i].bstrAttribute = ATTR_FRS_REPSET_TYPE;
  498. if (m_bNewSchema)
  499. {
  500. pAttributes[++i].bstrAttribute = ATTR_FRS_REPSET_TOPOLOGYPREF;
  501. pAttributes[++i].bstrAttribute = ATTR_FRS_REPSET_HUBSERVER;
  502. }
  503. pAttributes[++i].bstrAttribute = ATTR_FRS_REPSET_PRIMARYMEMBER;
  504. pAttributes[++i].bstrAttribute = ATTR_FRS_REPSET_FILEFILTER;
  505. pAttributes[++i].bstrAttribute = ATTR_FRS_REPSET_DIRFILTER;
  506. hr = GetValues( m_pldap,
  507. m_bstrReplicaSetDN,
  508. OBJCLASS_SF_NTFRSREPLICASET,
  509. LDAP_SCOPE_BASE,
  510. ++i,
  511. pAttributes,
  512. pValues);
  513. BREAK_IF_FAILED(hr);
  514. do {
  515. i = 0;
  516. if (pValues[i])
  517. {
  518. m_bstrType = (PTSTR)(pValues[i]->vpValue);
  519. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrType, &hr);
  520. }
  521. if (!m_bNewSchema)
  522. {
  523. m_bstrHubMemberDN.Empty();
  524. m_bstrTopologyPref = FRS_RSTOPOLOGYPREF_CUSTOM;
  525. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrTopologyPref, &hr);
  526. } else
  527. {
  528. i++;
  529. if (pValues[i])
  530. {
  531. m_bstrTopologyPref = (PTSTR)(pValues[i]->vpValue);
  532. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrTopologyPref, &hr);
  533. }
  534. i++;
  535. if (!lstrcmpi(FRS_RSTOPOLOGYPREF_HUBSPOKE, m_bstrTopologyPref))
  536. {
  537. if (pValues[i])
  538. {
  539. m_bstrHubMemberDN = (PTSTR)(pValues[i]->vpValue);
  540. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrHubMemberDN, &hr);
  541. } else
  542. {
  543. // something was wrong, reset Cutom topology
  544. m_bstrTopologyPref = FRS_RSTOPOLOGYPREF_CUSTOM;
  545. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrTopologyPref, &hr);
  546. }
  547. }
  548. }
  549. i++;
  550. if (pValues[i])
  551. {
  552. m_bstrPrimaryMemberDN = (PTSTR)(pValues[i]->vpValue);
  553. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrPrimaryMemberDN, &hr);
  554. }
  555. i++;
  556. if (pValues[i])
  557. {
  558. m_bstrFileFilter = (PTSTR)(pValues[i]->vpValue);
  559. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFileFilter, &hr);
  560. }
  561. i++;
  562. if (pValues[i])
  563. {
  564. m_bstrDirFilter = (PTSTR)(pValues[i]->vpValue);
  565. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDirFilter, &hr);
  566. }
  567. } while (0);
  568. for (i = 0; i < 7; i++)
  569. {
  570. if (pValues[i])
  571. FreeAttrValList(pValues[i]);
  572. }
  573. hr = _PopulateMemberList();
  574. BREAK_IF_FAILED(hr);
  575. hr = _PopulateConnectionList();
  576. BREAK_IF_FAILED(hr);
  577. dfsDebugOut((_T("members=%d, connections=%d\n"), m_frsMemberList.size(), m_frsConnectionList.size()));
  578. } while (0);
  579. if (FAILED(hr))
  580. _FreeMemberVariables();
  581. return hr;
  582. }
  583. HRESULT CReplicaSet::_PopulateMemberList()
  584. {
  585. PCTSTR ppszAttributes[] = {
  586. ATTR_DISTINGUISHEDNAME,
  587. ATTR_FRS_MEMBER_COMPUTERREF,
  588. 0
  589. };
  590. LListElem* pElem = NULL;
  591. HRESULT hr = GetValuesEx(
  592. m_pldap,
  593. m_bstrReplicaSetDN,
  594. LDAP_SCOPE_ONELEVEL,
  595. OBJCLASS_SF_NTFRSMEMBER,
  596. ppszAttributes,
  597. &pElem);
  598. RETURN_IF_FAILED(hr);
  599. LListElem* pCurElem = pElem;
  600. while (pCurElem)
  601. {
  602. PTSTR** pppszValues = pCurElem->pppszAttrValues;
  603. if (!pppszValues ||
  604. !pppszValues[0] || !*(pppszValues[0]) ||
  605. !pppszValues[1] || !*(pppszValues[1]))
  606. {
  607. pCurElem = pCurElem->Next;
  608. continue; // corrupted member object
  609. }
  610. CFrsMember *pMember = new CFrsMember;
  611. hr = pMember->InitEx(m_pldap,
  612. m_bstrDC,
  613. *(pppszValues[0]), // distinguishedName
  614. *(pppszValues[1]) // computerRef
  615. );
  616. if (FAILED(hr))
  617. {
  618. delete pMember;
  619. break;
  620. } else if (S_FALSE == hr)
  621. delete pMember;
  622. else
  623. m_frsMemberList.push_back(pMember);
  624. pCurElem = pCurElem->Next;
  625. }
  626. FreeLListElem(pElem);
  627. if (FAILED(hr))
  628. FreeFrsMembers(&m_frsMemberList);
  629. return hr;
  630. }
  631. STDMETHODIMP CReplicaSet::GetMemberList(
  632. /* [retval][out] */ VARIANT __RPC_FAR *pvarMemberDNs)
  633. {
  634. RETURN_INVALIDARG_IF_NULL(pvarMemberDNs);
  635. VariantInit(pvarMemberDNs);
  636. pvarMemberDNs->vt = VT_ARRAY | VT_VARIANT;
  637. pvarMemberDNs->parray = NULL;
  638. HRESULT hr = S_OK;
  639. int cMembers = m_frsMemberList.size();
  640. if (!cMembers)
  641. return hr; // parray is NULL when the member list is empty
  642. SAFEARRAYBOUND bounds = {cMembers, 0};
  643. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  644. RETURN_OUTOFMEMORY_IF_NULL(psa);
  645. VARIANT* varArray;
  646. SafeArrayAccessData(psa, (void**)&varArray);
  647. int i = 0;
  648. CFrsMemberList::iterator it;
  649. for (it = m_frsMemberList.begin(); (it != m_frsMemberList.end()) && (i < cMembers); it++, i++)
  650. {
  651. varArray[i].vt = VT_BSTR;
  652. varArray[i].bstrVal = ((*it)->m_bstrMemberDN).Copy();
  653. BREAK_OUTOFMEMORY_IF_NULL(varArray[i].bstrVal, &hr);
  654. }
  655. SafeArrayUnaccessData(psa);
  656. if (SUCCEEDED(hr))
  657. pvarMemberDNs->parray = psa;
  658. else
  659. SafeArrayDestroy(psa);
  660. return hr;
  661. }
  662. STDMETHODIMP CReplicaSet::GetMemberListEx(
  663. /* [retval][out] */ VARIANT __RPC_FAR *pVal)
  664. {
  665. RETURN_INVALIDARG_IF_NULL(pVal);
  666. VariantInit(pVal);
  667. pVal->vt = VT_ARRAY | VT_VARIANT;
  668. pVal->parray = NULL;
  669. HRESULT hr = S_OK;
  670. int cMembers = m_frsMemberList.size();
  671. if (!cMembers)
  672. return hr; // parray is NULL when the member list is empty
  673. SAFEARRAYBOUND bounds = {cMembers, 0};
  674. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  675. RETURN_OUTOFMEMORY_IF_NULL(psa);
  676. VARIANT* varArray;
  677. SafeArrayAccessData(psa, (void**)&varArray);
  678. int i = 0;
  679. CFrsMemberList::iterator it;
  680. for (it = m_frsMemberList.begin(); (it != m_frsMemberList.end()) && (i < cMembers); it++, i++)
  681. {
  682. VariantInit(&(varArray[i]));
  683. hr = _GetMemberInfo((*it), &(varArray[i]));
  684. BREAK_IF_FAILED(hr);
  685. }
  686. SafeArrayUnaccessData(psa);
  687. if (SUCCEEDED(hr))
  688. pVal->parray = psa;
  689. else
  690. SafeArrayDestroy(psa);
  691. return hr;
  692. }
  693. HRESULT CReplicaSet::_GetMemberInfo(
  694. IN CFrsMember* i_pFrsMember,
  695. OUT VARIANT* o_pvarMember)
  696. {
  697. RETURN_INVALIDARG_IF_NULL(i_pFrsMember);
  698. RETURN_INVALIDARG_IF_NULL(o_pvarMember);
  699. HRESULT hr = S_OK;
  700. SAFEARRAYBOUND bounds = {NUM_OF_FRSMEMBER_ATTRS, 0};
  701. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  702. RETURN_OUTOFMEMORY_IF_NULL(psa);
  703. VARIANT* varArray;
  704. SafeArrayAccessData(psa, (void**)&varArray);
  705. BSTR bstr[NUM_OF_FRSMEMBER_ATTRS] = {
  706. i_pFrsMember->m_bstrComputerDN,
  707. i_pFrsMember->m_bstrDomain,
  708. i_pFrsMember->m_bstrMemberDN,
  709. i_pFrsMember->m_bstrRootPath,
  710. i_pFrsMember->m_bstrServer,
  711. i_pFrsMember->m_bstrServerGuid,
  712. i_pFrsMember->m_bstrSite,
  713. i_pFrsMember->m_bstrStagingPath,
  714. i_pFrsMember->m_bstrSubscriberDN
  715. };
  716. for (int i = 0; i < NUM_OF_FRSMEMBER_ATTRS; i++)
  717. {
  718. varArray[i].vt = VT_BSTR;
  719. varArray[i].bstrVal = SysAllocString(bstr[i]);
  720. BREAK_OUTOFMEMORY_IF_NULL(varArray[i].bstrVal, &hr);
  721. }
  722. SafeArrayUnaccessData(psa);
  723. if (SUCCEEDED(hr))
  724. {
  725. o_pvarMember->vt = VT_ARRAY | VT_VARIANT;
  726. o_pvarMember->parray = psa;
  727. } else
  728. SafeArrayDestroy(psa);
  729. return hr;
  730. }
  731. STDMETHODIMP CReplicaSet::GetMemberInfo(
  732. /* [in] */ BSTR i_bstrMemberDN,
  733. /* [retval][out] */ VARIANT __RPC_FAR *o_pvarMember)
  734. {
  735. RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN);
  736. CFrsMemberList::iterator it;
  737. for (it = m_frsMemberList.begin(); it != m_frsMemberList.end(); it++)
  738. {
  739. if (!lstrcmpi(i_bstrMemberDN, (*it)->m_bstrMemberDN))
  740. break;
  741. }
  742. if (it == m_frsMemberList.end())
  743. return S_FALSE; // no such member
  744. return _GetMemberInfo((*it), o_pvarMember);
  745. }
  746. STDMETHODIMP CReplicaSet::GetBadMemberInfo(
  747. /* [in] */ BSTR i_bstrServerName,
  748. /* [retval][out] */ VARIANT __RPC_FAR *o_pvarMember)
  749. {
  750. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  751. int n = lstrlen(i_bstrServerName);
  752. int nLen = 0;
  753. int nMinLen = 0;
  754. CFrsMember* pMember = NULL;
  755. CFrsMemberList::iterator it;
  756. for (it = m_frsMemberList.begin(); it != m_frsMemberList.end(); it++)
  757. {
  758. if (!mylstrncmpi(i_bstrServerName, (*it)->m_bstrServer, n))
  759. {
  760. nLen = lstrlen((*it)->m_bstrServer);
  761. if (!pMember || nLen < nMinLen)
  762. {
  763. nMinLen = nLen;
  764. pMember = *it;
  765. }
  766. }
  767. }
  768. if (!pMember)
  769. return S_FALSE; // no such member
  770. return _GetMemberInfo(pMember, o_pvarMember);
  771. }
  772. STDMETHODIMP CReplicaSet::IsFRSMember(
  773. /* [in] */ BSTR i_bstrDnsHostName,
  774. /* [in] */ BSTR i_bstrRootPath
  775. )
  776. {
  777. if (!i_bstrDnsHostName || !*i_bstrDnsHostName ||
  778. !i_bstrRootPath || !*i_bstrRootPath)
  779. return S_FALSE;
  780. CFrsMemberList::iterator it;
  781. for (it = m_frsMemberList.begin(); it != m_frsMemberList.end(); it++)
  782. {
  783. if (!lstrcmpi(i_bstrDnsHostName, (*it)->m_bstrServer) &&
  784. !lstrcmpi(i_bstrRootPath, (*it)->m_bstrRootPath))
  785. break;
  786. }
  787. if (it == m_frsMemberList.end())
  788. return S_FALSE; // no such member
  789. return S_OK;
  790. }
  791. STDMETHODIMP CReplicaSet::IsHubMember(
  792. /* [in] */ BSTR i_bstrDnsHostName,
  793. /* [in] */ BSTR i_bstrRootPath
  794. )
  795. {
  796. if (!i_bstrDnsHostName || !*i_bstrDnsHostName ||
  797. !i_bstrRootPath || !*i_bstrRootPath)
  798. return S_FALSE;
  799. if (0 != lstrcmpi(FRS_RSTOPOLOGYPREF_HUBSPOKE, m_bstrTopologyPref))
  800. return S_FALSE; // not a hubspoke topology
  801. CFrsMemberList::iterator it;
  802. for (it = m_frsMemberList.begin(); it != m_frsMemberList.end(); it++)
  803. {
  804. if (!lstrcmpi(i_bstrDnsHostName, (*it)->m_bstrServer) &&
  805. !lstrcmpi(i_bstrRootPath, (*it)->m_bstrRootPath))
  806. break;
  807. }
  808. if (it == m_frsMemberList.end())
  809. return S_FALSE; // no such member
  810. if (!lstrcmpi(m_bstrHubMemberDN, (*it)->m_bstrMemberDN))
  811. return S_OK;
  812. return S_FALSE;
  813. }
  814. STDMETHODIMP CReplicaSet::AddMember(
  815. /* [in] */ BSTR i_bstrServer,
  816. /* [in] */ BSTR i_bstrRootPath,
  817. /* [in] */ BSTR i_bstrStagingPath,
  818. /* [in] */ BOOL i_bAddConnectionNow,
  819. /* [retval][out] */ BSTR __RPC_FAR *o_pbstrMemberDN)
  820. {
  821. CComBSTR bstrComputerDomain;
  822. CComBSTR bstrDnsHostName;
  823. CComBSTR bstrComputerGuid;
  824. CComBSTR bstrComputerDN;
  825. HRESULT hr = GetServerInfo(i_bstrServer,
  826. &bstrComputerDomain,
  827. NULL, //o_pbstrNetbiosName
  828. NULL, //o_pbValidDSObject
  829. &bstrDnsHostName,
  830. &bstrComputerGuid,
  831. &bstrComputerDN
  832. );
  833. if (S_OK != hr)
  834. return hr; // don't add this member if it doesn't have an appropriate computer obj in a domain
  835. //
  836. // is i_bstrServer already a frs member
  837. //
  838. BOOL bIsFrsMember = FALSE;
  839. for (CFrsMemberList::iterator i = m_frsMemberList.begin(); i != m_frsMemberList.end(); i++)
  840. {
  841. if (!lstrcmpi(bstrComputerGuid, (*i)->m_bstrServerGuid))
  842. {
  843. bIsFrsMember = TRUE;
  844. break;
  845. }
  846. }
  847. if (bIsFrsMember)
  848. {
  849. if (0 != lstrcmpi(i_bstrRootPath, (*i)->m_bstrRootPath))
  850. return S_FALSE; // cannot have two folders on the same computer join for the same replica set
  851. // member exists, return info of it
  852. if (o_pbstrMemberDN)
  853. {
  854. *o_pbstrMemberDN = (*i)->m_bstrMemberDN.Copy();
  855. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrMemberDN);
  856. }
  857. return hr;
  858. }
  859. //
  860. // find out if the computer object sits in the same domain as the member object
  861. //
  862. CComBSTR bstrDCofComputerObj;
  863. BOOL bSameDomain = FALSE;
  864. PLDAP pldapComputer = NULL;
  865. if (!lstrcmpi(bstrComputerDomain, m_bstrDomain))
  866. {
  867. bSameDomain = TRUE;
  868. pldapComputer = m_pldap;
  869. } else
  870. {
  871. hr = ConnectToDS(bstrComputerDomain, &pldapComputer, &bstrDCofComputerObj);
  872. RETURN_IF_FAILED(hr);
  873. }
  874. CComBSTR bstrMemberDN;
  875. CComBSTR bstrSubscriberDN;
  876. do {
  877. //
  878. // create a nTFRSMember object in the DS
  879. //
  880. bstrMemberDN = _T("CN=");
  881. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  882. bstrMemberDN += bstrComputerGuid;
  883. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  884. bstrMemberDN += _T(",");
  885. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  886. bstrMemberDN += m_bstrReplicaSetDN;
  887. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrMemberDN, &hr);
  888. hr = CreateNtfrsMemberObject(m_pldap, bstrMemberDN, bstrComputerDN, bstrDCofComputerObj);
  889. BREAK_IF_FAILED(hr);
  890. //
  891. // create a nTFRSSubscriber object in the DS
  892. //
  893. hr = GetSubscriberDN(m_bstrReplicaSetDN, m_bstrDomainGuid, bstrComputerDN, &bstrSubscriberDN);
  894. BREAK_IF_FAILED(hr);
  895. hr = CreateNtfrsSubscriptionsObjects(pldapComputer, bstrSubscriberDN, bstrComputerDN);
  896. BREAK_IF_FAILED(hr);
  897. hr = CreateNtfrsSubscriberObject(
  898. pldapComputer,
  899. bstrSubscriberDN,
  900. bstrMemberDN,
  901. i_bstrRootPath,
  902. i_bstrStagingPath,
  903. m_bstrDC
  904. );
  905. } while (0);
  906. if (!bSameDomain)
  907. CloseConnectionToDS(pldapComputer);
  908. RETURN_IF_FAILED(hr);
  909. //
  910. // add to m_frsMemberList
  911. //
  912. CFrsMember *pMember = new CFrsMember;
  913. hr = pMember->Init(
  914. bstrDnsHostName,
  915. bstrComputerDomain,
  916. bstrComputerGuid,
  917. i_bstrRootPath,
  918. i_bstrStagingPath,
  919. bstrMemberDN,
  920. bstrComputerDN,
  921. bstrSubscriberDN
  922. );
  923. if (FAILED(hr))
  924. {
  925. delete pMember;
  926. return hr;
  927. }
  928. m_frsMemberList.push_back(pMember);
  929. //
  930. // if TopologyPref is not custom, add connections
  931. //
  932. if (i_bAddConnectionNow)
  933. {
  934. hr = _AdjustConnectionsAdd(bstrMemberDN, pMember->m_bstrSite);
  935. RETURN_IF_FAILED(hr);
  936. }
  937. //
  938. // if o_pbstrMemberDN specified, return o_pbstrMemberDN
  939. //
  940. if (o_pbstrMemberDN)
  941. *o_pbstrMemberDN = bstrMemberDN.Detach();
  942. return hr;
  943. }
  944. HRESULT CReplicaSet::_DeleteMember(CFrsMember* pFrsMember)
  945. {
  946. HRESULT hr = S_OK;
  947. //
  948. // delete nTFRSSubscriber object
  949. //
  950. BOOL bSameDomain = FALSE;
  951. PLDAP pldapComputer = NULL;
  952. if (!lstrcmpi(pFrsMember->m_bstrDomain, m_bstrDomain))
  953. {
  954. bSameDomain = TRUE;
  955. pldapComputer = m_pldap;
  956. } else
  957. {
  958. hr = ConnectToDS(pFrsMember->m_bstrDomain, &pldapComputer, NULL);
  959. RETURN_IF_FAILED(hr);
  960. }
  961. hr = DeleteNtfrsSubscriberObjectAndContainers(
  962. pldapComputer,
  963. pFrsMember->m_bstrSubscriberDN,
  964. pFrsMember->m_bstrComputerDN);
  965. if (!bSameDomain)
  966. CloseConnectionToDS(pldapComputer);
  967. RETURN_IF_FAILED(hr);
  968. //
  969. // adjust connections based on current topologyPref
  970. //
  971. if (m_frsMemberList.size() <= 2)
  972. {
  973. hr = _SetCustomTopologyPref();
  974. } else if (!lstrcmpi(FRS_RSTOPOLOGYPREF_RING, m_bstrTopologyPref))
  975. {
  976. BSTR bstrMemberDN[2];
  977. int i = 0;
  978. CFrsConnectionList::iterator it;
  979. for (it = m_frsConnectionList.begin(); (it != m_frsConnectionList.end()) && (i < 2); it++)
  980. {
  981. if (!lstrcmpi(pFrsMember->m_bstrMemberDN, (*it)->m_bstrFromMemberDN))
  982. bstrMemberDN[i++] = (*it)->m_bstrToMemberDN;
  983. }
  984. if (i != 2)
  985. hr = _SetCustomTopologyPref(); // corrupted, reset to custom
  986. else
  987. {
  988. hr = AddConnection(bstrMemberDN[0], bstrMemberDN[1], TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  989. RETURN_IF_FAILED(hr);
  990. hr = AddConnection(bstrMemberDN[1], bstrMemberDN[0], TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  991. }
  992. }
  993. RETURN_IF_FAILED(hr);
  994. //
  995. // delete connections with other members
  996. //
  997. hr = _RemoveConnectionsFromAndTo(pFrsMember);
  998. RETURN_IF_FAILED(hr);
  999. //
  1000. // delete nTFRSMember object
  1001. //
  1002. hr = DeleteDSObject(m_pldap, pFrsMember->m_bstrMemberDN, TRUE);
  1003. return hr;
  1004. }
  1005. STDMETHODIMP CReplicaSet::RemoveMember(
  1006. /* [in] */ BSTR i_bstrMemberDN)
  1007. {
  1008. HRESULT hr = S_OK;
  1009. CFrsMemberList::iterator i;
  1010. for (i = m_frsMemberList.begin(); i != m_frsMemberList.end(); i++)
  1011. {
  1012. if (!lstrcmpi(i_bstrMemberDN, (*i)->m_bstrMemberDN))
  1013. break;
  1014. }
  1015. if (i == m_frsMemberList.end())
  1016. return hr; // no such member at all, return
  1017. //
  1018. // if it's the hub, change topologyPref to be custom
  1019. //
  1020. if (!lstrcmpi(FRS_RSTOPOLOGYPREF_HUBSPOKE, m_bstrTopologyPref) &&
  1021. !lstrcmpi(i_bstrMemberDN, m_bstrHubMemberDN))
  1022. {
  1023. hr = _SetCustomTopologyPref();
  1024. RETURN_IF_FAILED(hr);
  1025. }
  1026. //
  1027. // delete nTFRSSubscriber object
  1028. // adjust connections
  1029. // delete connections with other members
  1030. // delete nTFRSMember object
  1031. //
  1032. hr = _DeleteMember((*i));
  1033. //
  1034. // remove it from m_frsMemberList
  1035. //
  1036. delete (*i);
  1037. m_frsMemberList.erase(i);
  1038. return hr;
  1039. }
  1040. STDMETHODIMP CReplicaSet::RemoveMemberEx(
  1041. /* [in] */ BSTR i_bstrDnsHostName,
  1042. /* [in] */ BSTR i_bstrRootPath)
  1043. {
  1044. HRESULT hr = S_OK;
  1045. CFrsMemberList::iterator i;
  1046. for (i = m_frsMemberList.begin(); i != m_frsMemberList.end(); i++)
  1047. {
  1048. if (!lstrcmpi(i_bstrDnsHostName, (*i)->m_bstrServer) &&
  1049. !lstrcmpi(i_bstrRootPath, (*i)->m_bstrRootPath))
  1050. break;
  1051. }
  1052. if (i == m_frsMemberList.end())
  1053. return hr; // no such member at all, return
  1054. //
  1055. // if it's the hub, change topologyPref to be custom
  1056. //
  1057. if (!lstrcmpi(FRS_RSTOPOLOGYPREF_HUBSPOKE, m_bstrTopologyPref) &&
  1058. !lstrcmpi((*i)->m_bstrMemberDN, m_bstrHubMemberDN))
  1059. {
  1060. hr = _SetCustomTopologyPref();
  1061. RETURN_IF_FAILED(hr);
  1062. }
  1063. //
  1064. // delete nTFRSSubscriber object
  1065. // adjust connections
  1066. // delete connections with other members
  1067. // delete nTFRSMember object
  1068. //
  1069. hr = _DeleteMember((*i));
  1070. //
  1071. // remove it from m_frsMemberList
  1072. //
  1073. delete (*i);
  1074. m_frsMemberList.erase(i);
  1075. return hr;
  1076. }
  1077. STDMETHODIMP CReplicaSet::RemoveAllMembers()
  1078. {
  1079. HRESULT hr = S_OK;
  1080. CFrsMemberList::iterator i = m_frsMemberList.begin();
  1081. while (i != m_frsMemberList.end())
  1082. {
  1083. //
  1084. // delete nTFRSSubscriber object
  1085. // adjust connections
  1086. // delete connections with other members
  1087. // delete nTFRSMember object
  1088. //
  1089. hr = _DeleteMember((*i));
  1090. BREAK_IF_FAILED(hr);
  1091. //
  1092. // remove it from m_frsMemberList
  1093. //
  1094. delete (*i);
  1095. m_frsMemberList.erase(i);
  1096. i = m_frsMemberList.begin();
  1097. }
  1098. return hr;
  1099. }
  1100. HRESULT CReplicaSet::_PopulateConnectionList()
  1101. {
  1102. PCTSTR ppszAttributes[] = {
  1103. ATTR_DISTINGUISHEDNAME,
  1104. ATTR_NTDS_CONNECTION_FROMSERVER,
  1105. ATTR_NTDS_CONNECTION_ENABLEDCONNECTION,
  1106. ATTR_NTDS_CONNECTION_OPTIONS,
  1107. 0
  1108. };
  1109. LListElem* pElem = NULL;
  1110. HRESULT hr = GetValuesEx(
  1111. m_pldap,
  1112. m_bstrReplicaSetDN,
  1113. LDAP_SCOPE_SUBTREE,
  1114. OBJCLASS_SF_NTDSCONNECTION,
  1115. ppszAttributes,
  1116. &pElem);
  1117. RETURN_IF_FAILED(hr);
  1118. LListElem* pCurElem = pElem;
  1119. while (pCurElem)
  1120. {
  1121. PTSTR** pppszValues = pCurElem->pppszAttrValues;
  1122. if (!pppszValues ||
  1123. !pppszValues[0] || !*(pppszValues[0]) ||
  1124. !pppszValues[1] || !*(pppszValues[1]) ||
  1125. !pppszValues[2] || !*(pppszValues[2]))
  1126. {
  1127. pCurElem = pCurElem->Next;
  1128. continue; // corrupted connection object
  1129. }
  1130. PTSTR pszParentDN = _tcsstr(*(pppszValues[0]), _T(",CN="));
  1131. if (!pszParentDN)
  1132. {
  1133. pCurElem = pCurElem->Next;
  1134. continue; // corrupted connection object
  1135. }
  1136. pszParentDN++; // point to the 2nd CN=XXX
  1137. BOOL bFromServerFound = FALSE;
  1138. BOOL bToServerFound = FALSE;
  1139. CFrsMemberList::iterator i;
  1140. for (i = m_frsMemberList.begin(); i != m_frsMemberList.end(); i++)
  1141. {
  1142. if (!bToServerFound && !lstrcmpi(pszParentDN, (*i)->m_bstrMemberDN))
  1143. {
  1144. bToServerFound = TRUE;
  1145. }
  1146. if (!bFromServerFound && !lstrcmpi(*(pppszValues[1]), (*i)->m_bstrMemberDN))
  1147. {
  1148. bFromServerFound = TRUE;
  1149. }
  1150. }
  1151. if (!bFromServerFound || !bToServerFound)
  1152. {
  1153. pCurElem = pCurElem->Next;
  1154. continue; // unknown fromServer or toServer, skip this connection
  1155. }
  1156. DWORD dwOptions = _tcstoul(*(pppszValues[3]), NULL, 10);
  1157. BOOL bEnable = (CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, *(pppszValues[2]), -1, CONNECTION_ENABLED_TRUE, -1));
  1158. CFrsConnection* pFrsConnection = new CFrsConnection;
  1159. BREAK_OUTOFMEMORY_IF_NULL(pFrsConnection, &hr);
  1160. hr = pFrsConnection->Init(
  1161. *(pppszValues[0]), // FQDN
  1162. *(pppszValues[1]), // fromServer
  1163. bEnable, // enableConnection
  1164. dwOptions // options
  1165. );
  1166. if (FAILED(hr))
  1167. {
  1168. delete pFrsConnection;
  1169. break;
  1170. }
  1171. m_frsConnectionList.push_back(pFrsConnection);
  1172. pCurElem = pCurElem->Next;
  1173. }
  1174. FreeLListElem(pElem);
  1175. if (FAILED(hr))
  1176. FreeFrsConnections(&m_frsConnectionList);
  1177. return hr;
  1178. }
  1179. STDMETHODIMP CReplicaSet::GetConnectionList(
  1180. /* [retval][out] */ VARIANT __RPC_FAR *o_pvarConnectionDNs)
  1181. {
  1182. RETURN_INVALIDARG_IF_NULL(o_pvarConnectionDNs);
  1183. VariantInit(o_pvarConnectionDNs);
  1184. o_pvarConnectionDNs->vt = VT_ARRAY | VT_VARIANT;
  1185. o_pvarConnectionDNs->parray = NULL;
  1186. HRESULT hr = S_OK;
  1187. int cConnections = m_frsConnectionList.size();
  1188. if (!cConnections)
  1189. return hr; // parray is NULL when the connection list is empty
  1190. SAFEARRAYBOUND bounds = {cConnections, 0};
  1191. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  1192. RETURN_OUTOFMEMORY_IF_NULL(psa);
  1193. VARIANT* varArray;
  1194. SafeArrayAccessData(psa, (void**)&varArray);
  1195. int i = 0;
  1196. CFrsConnectionList::iterator it;
  1197. for (it = m_frsConnectionList.begin(); (it != m_frsConnectionList.end()) && (i < cConnections); it++, i++)
  1198. {
  1199. varArray[i].vt = VT_BSTR;
  1200. varArray[i].bstrVal = ((*it)->m_bstrConnectionDN).Copy();
  1201. BREAK_OUTOFMEMORY_IF_NULL(varArray[i].bstrVal, &hr);
  1202. }
  1203. SafeArrayUnaccessData(psa);
  1204. if (SUCCEEDED(hr))
  1205. o_pvarConnectionDNs->parray = psa;
  1206. else
  1207. SafeArrayDestroy(psa);
  1208. return hr;
  1209. }
  1210. STDMETHODIMP CReplicaSet::GetConnectionListEx(
  1211. /* [retval][out] */ VARIANT __RPC_FAR *pVal)
  1212. {
  1213. RETURN_INVALIDARG_IF_NULL(pVal);
  1214. VariantInit(pVal);
  1215. pVal->vt = VT_ARRAY | VT_VARIANT;
  1216. pVal->parray = NULL;
  1217. HRESULT hr = S_OK;
  1218. int cConnections = m_frsConnectionList.size();
  1219. if (!cConnections)
  1220. return hr; // parray is NULL when the connection list is empty
  1221. SAFEARRAYBOUND bounds = {cConnections, 0};
  1222. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  1223. RETURN_OUTOFMEMORY_IF_NULL(psa);
  1224. VARIANT* varArray;
  1225. SafeArrayAccessData(psa, (void**)&varArray);
  1226. int i = 0;
  1227. CFrsConnectionList::iterator it;
  1228. for (it = m_frsConnectionList.begin(); (it != m_frsConnectionList.end()) && (i < cConnections); it++, i++)
  1229. {
  1230. VariantInit(&(varArray[i]));
  1231. hr = _GetConnectionInfo((*it), &(varArray[i]));
  1232. BREAK_IF_FAILED(hr);
  1233. }
  1234. SafeArrayUnaccessData(psa);
  1235. if (SUCCEEDED(hr))
  1236. pVal->parray = psa;
  1237. else
  1238. SafeArrayDestroy(psa);
  1239. return hr;
  1240. }
  1241. HRESULT CReplicaSet::_GetConnectionInfo(
  1242. IN CFrsConnection* i_pFrsConnection,
  1243. OUT VARIANT* o_pvarConnection)
  1244. {
  1245. RETURN_INVALIDARG_IF_NULL(i_pFrsConnection);
  1246. RETURN_INVALIDARG_IF_NULL(o_pvarConnection);
  1247. HRESULT hr = S_OK;
  1248. SAFEARRAYBOUND bounds = {NUM_OF_FRSCONNECTION_ATTRS, 0};
  1249. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  1250. RETURN_OUTOFMEMORY_IF_NULL(psa);
  1251. VARIANT* varArray;
  1252. SafeArrayAccessData(psa, (void**)&varArray);
  1253. BSTR bstr[NUM_OF_FRSCONNECTION_ATTRS - 2] = {
  1254. i_pFrsConnection->m_bstrConnectionDN,
  1255. i_pFrsConnection->m_bstrFromMemberDN,
  1256. i_pFrsConnection->m_bstrToMemberDN
  1257. };
  1258. for (int i = 0; i < NUM_OF_FRSCONNECTION_ATTRS - 2; i++)
  1259. {
  1260. varArray[i].vt = VT_BSTR;
  1261. varArray[i].bstrVal = SysAllocString(bstr[i]);
  1262. BREAK_OUTOFMEMORY_IF_NULL(varArray[i].bstrVal, &hr);
  1263. }
  1264. if (SUCCEEDED(hr))
  1265. {
  1266. varArray[i].vt = VT_I4;
  1267. varArray[i].lVal = (long)(i_pFrsConnection->m_bEnable);
  1268. varArray[++i].vt = VT_I4;
  1269. varArray[i].lVal = (long)(i_pFrsConnection->m_dwOptions);
  1270. }
  1271. SafeArrayUnaccessData(psa);
  1272. if (SUCCEEDED(hr))
  1273. {
  1274. o_pvarConnection->vt = VT_ARRAY | VT_VARIANT;
  1275. o_pvarConnection->parray = psa;
  1276. } else
  1277. SafeArrayDestroy(psa);
  1278. return S_OK;
  1279. }
  1280. STDMETHODIMP CReplicaSet::GetConnectionInfo(
  1281. /* [in] */ BSTR i_bstrConnectionDN,
  1282. /* [retval][out] */ VARIANT __RPC_FAR *o_pvarConnection)
  1283. {
  1284. RETURN_INVALIDARG_IF_NULL(i_bstrConnectionDN);
  1285. CFrsConnectionList::iterator it;
  1286. for (it = m_frsConnectionList.begin(); it != m_frsConnectionList.end(); it++)
  1287. {
  1288. if (!lstrcmpi(i_bstrConnectionDN, (*it)->m_bstrConnectionDN))
  1289. break;
  1290. }
  1291. if (it == m_frsConnectionList.end())
  1292. return S_FALSE;
  1293. return _GetConnectionInfo((*it), o_pvarConnection);
  1294. }
  1295. STDMETHODIMP CReplicaSet::AddConnection(
  1296. /* [in] */ BSTR i_bstrFromMemberDN,
  1297. /* [in] */ BSTR i_bstrToMemberDN,
  1298. /* [in] */ BOOL i_bEnable,
  1299. /* [in] */ BOOL i_bSyncImmediately,
  1300. /* [in] */ long i_nPriority,
  1301. /* [retval][out] */ BSTR __RPC_FAR *o_pbstrConnectionDN)
  1302. {
  1303. if (!lstrcmpi(i_bstrFromMemberDN, i_bstrToMemberDN))
  1304. return S_OK;
  1305. HRESULT hr = S_OK;
  1306. //
  1307. // is it an existing connection?
  1308. //
  1309. BOOL bIsFrsConnection = FALSE;
  1310. CFrsConnectionList::iterator i;
  1311. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1312. {
  1313. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1314. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1315. {
  1316. bIsFrsConnection = TRUE;
  1317. break;
  1318. }
  1319. }
  1320. if (bIsFrsConnection)
  1321. {
  1322. // connection exists, return info of it
  1323. if (o_pbstrConnectionDN)
  1324. {
  1325. *o_pbstrConnectionDN = (*i)->m_bstrConnectionDN.Copy();
  1326. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrConnectionDN);
  1327. }
  1328. return hr;
  1329. }
  1330. //
  1331. // locate the fromMember and the toMember in the m_frsMemberList
  1332. //
  1333. CFrsMemberList::iterator from;
  1334. for (from = m_frsMemberList.begin(); from != m_frsMemberList.end(); from++)
  1335. {
  1336. if (!lstrcmpi(i_bstrFromMemberDN, (*from)->m_bstrMemberDN))
  1337. break;
  1338. }
  1339. if (from == m_frsMemberList.end())
  1340. {
  1341. // fromServer is not a frsMember yet
  1342. return E_INVALIDARG;
  1343. }
  1344. CFrsMemberList::iterator to;
  1345. for (to = m_frsMemberList.begin(); to != m_frsMemberList.end(); to++)
  1346. {
  1347. if (!lstrcmpi(i_bstrToMemberDN, (*to)->m_bstrMemberDN))
  1348. break;
  1349. }
  1350. if (to == m_frsMemberList.end())
  1351. {
  1352. // toServer is not a frsMember yet
  1353. return E_INVALIDARG;
  1354. }
  1355. //
  1356. // create the nTDSConnection object
  1357. //
  1358. CComBSTR bstrConnectionDN = _T("CN=");
  1359. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrConnectionDN);
  1360. bstrConnectionDN += (*from)->m_bstrServerGuid;
  1361. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrConnectionDN);
  1362. bstrConnectionDN += _T(",");
  1363. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrConnectionDN);
  1364. bstrConnectionDN += (*to)->m_bstrMemberDN;
  1365. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrConnectionDN);
  1366. DWORD dwOptions = (i_bSyncImmediately ? 0x80000000 : 0x0);
  1367. switch (i_nPriority)
  1368. {
  1369. case 1:
  1370. case 2:
  1371. dwOptions |= (PRIORITY_HIGH << 28);
  1372. break;
  1373. case 3:
  1374. case 4:
  1375. dwOptions |= (PRIORITY_MEDIUM << 28);
  1376. break;
  1377. default:
  1378. dwOptions |= (PRIORITY_LOW << 28);
  1379. break;
  1380. }
  1381. hr = CreateNtdsConnectionObject(
  1382. m_pldap,
  1383. bstrConnectionDN,
  1384. i_bstrFromMemberDN,
  1385. i_bEnable,
  1386. dwOptions
  1387. );
  1388. RETURN_IF_FAILED(hr);
  1389. //
  1390. // add to m_frsConnectionList
  1391. //
  1392. CFrsConnection* pFrsConnection = new CFrsConnection;
  1393. RETURN_OUTOFMEMORY_IF_NULL(pFrsConnection);
  1394. hr = pFrsConnection->Init(
  1395. bstrConnectionDN, // FQDN
  1396. i_bstrFromMemberDN, // fromServer
  1397. i_bEnable, // enableConnection
  1398. dwOptions);
  1399. if (FAILED(hr))
  1400. {
  1401. delete pFrsConnection;
  1402. return hr;
  1403. }
  1404. m_frsConnectionList.push_back(pFrsConnection);
  1405. //
  1406. // if o_pbstrConnectionDN specified, return o_pbstrConnectionDN
  1407. //
  1408. if (o_pbstrConnectionDN)
  1409. *o_pbstrConnectionDN = bstrConnectionDN.Detach();
  1410. return hr;
  1411. }
  1412. STDMETHODIMP CReplicaSet::RemoveConnection(
  1413. /* [in] */ BSTR i_bstrConnectionDN)
  1414. {
  1415. HRESULT hr = S_OK;
  1416. //
  1417. // locate connection in the m_frsConnectionList
  1418. //
  1419. CFrsConnectionList::iterator i;
  1420. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1421. {
  1422. if (!lstrcmpi(i_bstrConnectionDN, (*i)->m_bstrConnectionDN))
  1423. break;
  1424. }
  1425. if (i == m_frsConnectionList.end())
  1426. return hr; // no such connection, return
  1427. //
  1428. // delete the nTDSConnection object
  1429. //
  1430. hr = DeleteDSObject(m_pldap, (*i)->m_bstrConnectionDN, TRUE);
  1431. RETURN_IF_FAILED(hr);
  1432. //
  1433. // remove it from m_frsConnectionList
  1434. //
  1435. delete (*i);
  1436. m_frsConnectionList.erase(i);
  1437. return hr;
  1438. }
  1439. STDMETHODIMP CReplicaSet::RemoveConnectionEx(
  1440. /* [in] */ BSTR i_bstrFromMemberDN,
  1441. /* [in] */ BSTR i_bstrToMemberDN)
  1442. {
  1443. HRESULT hr = S_OK;
  1444. //
  1445. // locate connection in the m_frsConnectionList
  1446. //
  1447. CFrsConnectionList::iterator i;
  1448. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1449. {
  1450. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1451. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1452. break;
  1453. }
  1454. if (i == m_frsConnectionList.end())
  1455. return hr; // no such connection, return
  1456. //
  1457. // delete the nTDSConnection object
  1458. //
  1459. hr = DeleteDSObject(m_pldap, (*i)->m_bstrConnectionDN, TRUE);
  1460. RETURN_IF_FAILED(hr);
  1461. //
  1462. // remove it from m_frsConnectionList
  1463. //
  1464. delete (*i);
  1465. m_frsConnectionList.erase(i);
  1466. return hr;
  1467. }
  1468. STDMETHODIMP CReplicaSet::RemoveAllConnections()
  1469. {
  1470. HRESULT hr = S_OK;
  1471. CFrsConnectionList::iterator i = m_frsConnectionList.begin();
  1472. while (i != m_frsConnectionList.end())
  1473. {
  1474. //
  1475. // delete the nTDSConnection object
  1476. //
  1477. hr = DeleteDSObject(m_pldap, (*i)->m_bstrConnectionDN, TRUE);
  1478. BREAK_IF_FAILED(hr);
  1479. //
  1480. // remove it from m_frsConnectionList
  1481. //
  1482. delete (*i);
  1483. m_frsConnectionList.erase(i);
  1484. i = m_frsConnectionList.begin();
  1485. }
  1486. return hr;
  1487. }
  1488. HRESULT CReplicaSet::_RemoveConnectionsFromAndTo(CFrsMember* pFrsMember)
  1489. {
  1490. RETURN_INVALIDARG_IF_NULL(pFrsMember);
  1491. HRESULT hr = S_OK;
  1492. CFrsConnectionList::iterator i = m_frsConnectionList.begin();
  1493. while (i != m_frsConnectionList.end())
  1494. {
  1495. CFrsConnectionList::iterator itConn = i++;
  1496. if (!lstrcmpi(pFrsMember->m_bstrMemberDN, (*itConn)->m_bstrFromMemberDN) ||
  1497. !lstrcmpi(pFrsMember->m_bstrMemberDN, (*itConn)->m_bstrToMemberDN))
  1498. {
  1499. //
  1500. // delete the nTDSConnection object
  1501. //
  1502. hr = DeleteDSObject(m_pldap, (*itConn)->m_bstrConnectionDN, TRUE);
  1503. RETURN_IF_FAILED(hr);
  1504. //
  1505. // remove it from m_frsConnectionList
  1506. //
  1507. delete (*itConn);
  1508. m_frsConnectionList.erase(itConn);
  1509. }
  1510. }
  1511. return hr;
  1512. }
  1513. STDMETHODIMP CReplicaSet::EnableConnection(
  1514. /* [in] */ BSTR i_bstrConnectionDN,
  1515. /* [in] */ BOOL i_bEnable)
  1516. {
  1517. HRESULT hr = S_OK;
  1518. //
  1519. // locate connection in the m_frsConnectionList
  1520. //
  1521. CFrsConnectionList::iterator i;
  1522. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1523. {
  1524. if (!lstrcmpi(i_bstrConnectionDN, (*i)->m_bstrConnectionDN))
  1525. break;
  1526. }
  1527. if (i == m_frsConnectionList.end())
  1528. return E_INVALIDARG; // no such conneciton, return error
  1529. //
  1530. // update attribute enabledConnection of this nTDSConnection object
  1531. //
  1532. LDAP_ATTR_VALUE pAttrVals[1];
  1533. pAttrVals[0].bstrAttribute = ATTR_NTDS_CONNECTION_ENABLEDCONNECTION;
  1534. pAttrVals[0].vpValue = (void *)(i_bEnable ? CONNECTION_ENABLED_TRUE : CONNECTION_ENABLED_FALSE);
  1535. pAttrVals[0].bBerValue = false;
  1536. hr = ::ModifyValues(m_pldap, (*i)->m_bstrConnectionDN, 1, pAttrVals);
  1537. //
  1538. // update i in the m_frsConnectionList
  1539. //
  1540. if (SUCCEEDED(hr))
  1541. (*i)->m_bEnable = i_bEnable;
  1542. return hr;
  1543. }
  1544. STDMETHODIMP CReplicaSet::EnableConnectionEx(
  1545. /* [in] */ BSTR i_bstrFromMemberDN,
  1546. /* [in] */ BSTR i_bstrToMemberDN,
  1547. /* [in] */ BOOL i_bEnable)
  1548. {
  1549. HRESULT hr = S_OK;
  1550. //
  1551. // locate connection in the m_frsConnectionList
  1552. //
  1553. CFrsConnectionList::iterator i;
  1554. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1555. {
  1556. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1557. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1558. break;
  1559. }
  1560. if (i == m_frsConnectionList.end())
  1561. return E_INVALIDARG; // no such conneciton, return error
  1562. //
  1563. // update attribute enabledConnection of this nTDSConnection object
  1564. //
  1565. LDAP_ATTR_VALUE pAttrVals[1];
  1566. pAttrVals[0].bstrAttribute = ATTR_NTDS_CONNECTION_ENABLEDCONNECTION;
  1567. pAttrVals[0].vpValue = (void *)(i_bEnable ? CONNECTION_ENABLED_TRUE : CONNECTION_ENABLED_FALSE);
  1568. pAttrVals[0].bBerValue = false;
  1569. hr = ::ModifyValues(m_pldap, (*i)->m_bstrConnectionDN, 1, pAttrVals);
  1570. //
  1571. // update i in the m_frsConnectionList
  1572. //
  1573. if (SUCCEEDED(hr))
  1574. (*i)->m_bEnable = i_bEnable;
  1575. return hr;
  1576. }
  1577. HRESULT CReplicaSet::_GetConnectionSchedule(
  1578. /* [in] */ BSTR i_bstrConnectionDN,
  1579. /* [retval][out] */ VARIANT* o_pVar)
  1580. {
  1581. //
  1582. // get attribute schedule of this nTDSConnection object
  1583. //
  1584. PLDAP_ATTR_VALUE pValues[2] = {0,0};
  1585. LDAP_ATTR_VALUE pAttributes[1];
  1586. pAttributes[0].bstrAttribute = ATTR_NTDS_CONNECTION_SCHEDULE;
  1587. pAttributes[0].bBerValue = true;
  1588. HRESULT hr = GetValues( m_pldap,
  1589. i_bstrConnectionDN,
  1590. OBJCLASS_SF_NTDSCONNECTION,
  1591. LDAP_SCOPE_BASE,
  1592. 1,
  1593. pAttributes,
  1594. pValues);
  1595. if (SUCCEEDED(hr) && pValues[0])
  1596. {
  1597. hr = ScheduleToVariant((SCHEDULE *)(pValues[0]->vpValue), o_pVar);
  1598. FreeAttrValList(pValues[0]);
  1599. } else if (!(pValues[0]) || HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED) == hr)
  1600. {
  1601. SCHEDULE *pSchedule = NULL;
  1602. hr = GetDefaultSchedule(&pSchedule);
  1603. if (SUCCEEDED(hr))
  1604. {
  1605. hr = ScheduleToVariant(pSchedule, o_pVar);
  1606. free(pSchedule);
  1607. }
  1608. }
  1609. return hr;
  1610. }
  1611. STDMETHODIMP CReplicaSet::GetConnectionSchedule(
  1612. /* [in] */ BSTR i_bstrConnectionDN,
  1613. /* [retval][out] */ VARIANT* o_pVar)
  1614. {
  1615. RETURN_INVALIDARG_IF_NULL(i_bstrConnectionDN);
  1616. RETURN_INVALIDARG_IF_NULL(o_pVar);
  1617. //
  1618. // locate connection in the m_frsConnectionList
  1619. //
  1620. CFrsConnectionList::iterator i;
  1621. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1622. {
  1623. if (!lstrcmpi(i_bstrConnectionDN, (*i)->m_bstrConnectionDN))
  1624. break;
  1625. }
  1626. if (i == m_frsConnectionList.end())
  1627. return E_INVALIDARG; // no such conneciton, return error
  1628. return _GetConnectionSchedule(i_bstrConnectionDN, o_pVar);
  1629. }
  1630. STDMETHODIMP CReplicaSet::GetConnectionScheduleEx(
  1631. /* [in] */ BSTR i_bstrFromMemberDN,
  1632. /* [in] */ BSTR i_bstrToMemberDN,
  1633. /* [retval][out] */ VARIANT* o_pVar)
  1634. {
  1635. RETURN_INVALIDARG_IF_NULL(i_bstrFromMemberDN);
  1636. RETURN_INVALIDARG_IF_NULL(i_bstrToMemberDN);
  1637. RETURN_INVALIDARG_IF_NULL(o_pVar);
  1638. //
  1639. // locate connection in the m_frsConnectionList
  1640. //
  1641. CFrsConnectionList::iterator i;
  1642. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1643. {
  1644. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1645. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1646. break;
  1647. }
  1648. if (i == m_frsConnectionList.end())
  1649. return E_INVALIDARG; // no such conneciton, return error
  1650. return _GetConnectionSchedule((*i)->m_bstrConnectionDN, o_pVar);
  1651. }
  1652. STDMETHODIMP CReplicaSet::SetConnectionSchedule(
  1653. /* [in] */ BSTR i_bstrConnectionDN,
  1654. /* [in] */ VARIANT* i_pVar)
  1655. {
  1656. RETURN_INVALIDARG_IF_NULL(i_bstrConnectionDN);
  1657. RETURN_INVALIDARG_IF_NULL(i_pVar);
  1658. HRESULT hr = S_OK;
  1659. //
  1660. // locate connection in the m_frsConnectionList
  1661. //
  1662. CFrsConnectionList::iterator i;
  1663. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1664. {
  1665. if (!lstrcmpi(i_bstrConnectionDN, (*i)->m_bstrConnectionDN))
  1666. break;
  1667. }
  1668. if (i == m_frsConnectionList.end())
  1669. return E_INVALIDARG; // no such conneciton, return error
  1670. SCHEDULE *pSchedule = NULL;
  1671. hr = VariantToSchedule(i_pVar, &pSchedule);
  1672. RETURN_IF_FAILED(hr);
  1673. hr = ::SetConnectionSchedule(m_pldap, (*i)->m_bstrConnectionDN, pSchedule);
  1674. free(pSchedule);
  1675. return hr;
  1676. }
  1677. STDMETHODIMP CReplicaSet::SetConnectionScheduleEx(
  1678. /* [in] */ BSTR i_bstrFromMemberDN,
  1679. /* [in] */ BSTR i_bstrToMemberDN,
  1680. /* [in] */ VARIANT* i_pVar)
  1681. {
  1682. RETURN_INVALIDARG_IF_NULL(i_bstrFromMemberDN);
  1683. RETURN_INVALIDARG_IF_NULL(i_bstrToMemberDN);
  1684. RETURN_INVALIDARG_IF_NULL(i_pVar);
  1685. HRESULT hr = S_OK;
  1686. //
  1687. // locate connection in the m_frsConnectionList
  1688. //
  1689. CFrsConnectionList::iterator i;
  1690. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1691. {
  1692. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1693. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1694. break;
  1695. }
  1696. if (i == m_frsConnectionList.end())
  1697. return E_INVALIDARG; // no such conneciton, return error
  1698. SCHEDULE *pSchedule = NULL;
  1699. hr = VariantToSchedule(i_pVar, &pSchedule);
  1700. RETURN_IF_FAILED(hr);
  1701. hr = ::SetConnectionSchedule(m_pldap, (*i)->m_bstrConnectionDN, pSchedule);
  1702. free(pSchedule);
  1703. return hr;
  1704. }
  1705. STDMETHODIMP CReplicaSet::SetScheduleOnAllConnections(
  1706. /* [in] */ VARIANT* i_pVar)
  1707. {
  1708. RETURN_INVALIDARG_IF_NULL(i_pVar);
  1709. HRESULT hr = S_OK;
  1710. SCHEDULE *pSchedule = NULL;
  1711. hr = VariantToSchedule(i_pVar, &pSchedule);
  1712. RETURN_IF_FAILED(hr);
  1713. CFrsConnectionList::iterator i;
  1714. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1715. {
  1716. hr = ::SetConnectionSchedule(m_pldap, (*i)->m_bstrConnectionDN, pSchedule);
  1717. BREAK_IF_FAILED(hr);
  1718. }
  1719. free(pSchedule);
  1720. return hr;
  1721. }
  1722. STDMETHODIMP CReplicaSet::SetConnectionOptions(
  1723. /* [in] */ BSTR i_bstrConnectionDN,
  1724. /* [in] */ BOOL i_bSyncImmediately,
  1725. /* [in] */ long i_nPriority)
  1726. {
  1727. RETURN_INVALIDARG_IF_NULL(i_bstrConnectionDN);
  1728. HRESULT hr = S_OK;
  1729. //
  1730. // locate connection in the m_frsConnectionList
  1731. //
  1732. CFrsConnectionList::iterator i;
  1733. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1734. {
  1735. if (!lstrcmpi(i_bstrConnectionDN, (*i)->m_bstrConnectionDN))
  1736. break;
  1737. }
  1738. if (i == m_frsConnectionList.end())
  1739. return E_INVALIDARG; // no such conneciton, return error
  1740. DWORD dwOptions = (i_bSyncImmediately ? 0x80000000 : 0x0);
  1741. switch (i_nPriority)
  1742. {
  1743. case 1:
  1744. case 2:
  1745. dwOptions |= (PRIORITY_HIGH << 28);
  1746. break;
  1747. case 3:
  1748. case 4:
  1749. dwOptions |= (PRIORITY_MEDIUM << 28);
  1750. break;
  1751. default:
  1752. dwOptions |= (PRIORITY_LOW << 28);
  1753. break;
  1754. }
  1755. hr = ::SetConnectionOptions(m_pldap, (*i)->m_bstrConnectionDN, dwOptions);
  1756. if (SUCCEEDED(hr))
  1757. {
  1758. //
  1759. // update m_dwOptions in the m_frsConnectionList
  1760. //
  1761. if (SUCCEEDED(hr))
  1762. (*i)->m_dwOptions = dwOptions;
  1763. }
  1764. return hr;
  1765. }
  1766. STDMETHODIMP CReplicaSet::SetConnectionOptionsEx(
  1767. /* [in] */ BSTR i_bstrFromMemberDN,
  1768. /* [in] */ BSTR i_bstrToMemberDN,
  1769. /* [in] */ BOOL i_bSyncImmediately,
  1770. /* [in] */ long i_nPriority)
  1771. {
  1772. RETURN_INVALIDARG_IF_NULL(i_bstrFromMemberDN);
  1773. RETURN_INVALIDARG_IF_NULL(i_bstrToMemberDN);
  1774. HRESULT hr = S_OK;
  1775. //
  1776. // locate connection in the m_frsConnectionList
  1777. //
  1778. CFrsConnectionList::iterator i;
  1779. for (i = m_frsConnectionList.begin(); i != m_frsConnectionList.end(); i++)
  1780. {
  1781. if (!lstrcmpi(i_bstrFromMemberDN, (*i)->m_bstrFromMemberDN) &&
  1782. !lstrcmpi(i_bstrToMemberDN, (*i)->m_bstrToMemberDN))
  1783. break;
  1784. }
  1785. if (i == m_frsConnectionList.end())
  1786. return E_INVALIDARG; // no such conneciton, return error
  1787. DWORD dwOptions = (i_bSyncImmediately ? 0x80000000 : 0x0);
  1788. switch (i_nPriority)
  1789. {
  1790. case 1:
  1791. case 2:
  1792. dwOptions |= (PRIORITY_HIGH << 28);
  1793. break;
  1794. case 3:
  1795. case 4:
  1796. dwOptions |= (PRIORITY_MEDIUM << 28);
  1797. break;
  1798. default:
  1799. dwOptions |= (PRIORITY_LOW << 28);
  1800. break;
  1801. }
  1802. hr = ::SetConnectionOptions(m_pldap, (*i)->m_bstrConnectionDN, dwOptions);
  1803. if (SUCCEEDED(hr))
  1804. {
  1805. //
  1806. // update m_dwOptions in the m_frsConnectionList
  1807. //
  1808. if (SUCCEEDED(hr))
  1809. (*i)->m_dwOptions = dwOptions;
  1810. }
  1811. return hr;
  1812. }
  1813. STDMETHODIMP CReplicaSet::CreateConnections()
  1814. {
  1815. HRESULT hr = S_OK;
  1816. //
  1817. // create connections from scratch
  1818. //
  1819. if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_CUSTOM))
  1820. return hr;
  1821. CFrsMemberList::iterator n1;
  1822. CFrsMemberList::iterator n2;
  1823. if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_RING))
  1824. {
  1825. //
  1826. // sort member list on Site, such that members on the same site will be neighbors
  1827. //
  1828. m_frsMemberList.sort(FrsMemberCompare());
  1829. CFrsMemberList::iterator head;
  1830. head = n1 = m_frsMemberList.begin();
  1831. while (n1 != m_frsMemberList.end())
  1832. {
  1833. n2 = n1++;
  1834. if (n1 == m_frsMemberList.end())
  1835. {
  1836. if (m_frsMemberList.size() == 2)
  1837. break;
  1838. n1 = head;
  1839. }
  1840. hr = AddConnection((*n1)->m_bstrMemberDN, (*n2)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1841. BREAK_IF_FAILED(hr);
  1842. hr = AddConnection((*n2)->m_bstrMemberDN, (*n1)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1843. BREAK_IF_FAILED(hr);
  1844. if (n1 == head)
  1845. break;
  1846. }
  1847. } else if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE))
  1848. {
  1849. for (n1 = m_frsMemberList.begin(); n1 != m_frsMemberList.end(); n1++)
  1850. {
  1851. if (!lstrcmpi((*n1)->m_bstrMemberDN, m_bstrHubMemberDN))
  1852. continue;
  1853. hr = AddConnection((*n1)->m_bstrMemberDN, m_bstrHubMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1854. BREAK_IF_FAILED(hr);
  1855. hr = AddConnection(m_bstrHubMemberDN, (*n1)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1856. BREAK_IF_FAILED(hr);
  1857. }
  1858. } else if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_FULLMESH))
  1859. {
  1860. for (n1 = m_frsMemberList.begin(); n1 != m_frsMemberList.end(); n1++)
  1861. {
  1862. for (n2 = m_frsMemberList.begin(); n2 != m_frsMemberList.end(); n2++)
  1863. {
  1864. if (!lstrcmpi((*n1)->m_bstrMemberDN, (*n2)->m_bstrMemberDN))
  1865. continue;
  1866. hr = AddConnection((*n1)->m_bstrMemberDN, (*n2)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1867. BREAK_IF_FAILED(hr);
  1868. }
  1869. BREAK_IF_FAILED(hr);
  1870. }
  1871. }
  1872. return hr;
  1873. }
  1874. STDMETHODIMP CReplicaSet::Delete()
  1875. {
  1876. dfsDebugOut((_T("Delete ReplicaSet: %s\n"), m_bstrReplicaSetDN));
  1877. HRESULT hr = S_OK;
  1878. //
  1879. // delete all connections
  1880. //
  1881. hr = RemoveAllConnections();
  1882. RETURN_IF_FAILED(hr);
  1883. //
  1884. // delete all members
  1885. //
  1886. // Note: the nTFRSReplicaSet object will be deleted if empty
  1887. //
  1888. hr = RemoveAllMembers();
  1889. RETURN_IF_FAILED(hr);
  1890. //
  1891. // delete nTFRSReplicaSettings container objects if empty
  1892. //
  1893. (void) DeleteNtfrsReplicaSetObjectAndContainers(m_pldap, m_bstrReplicaSetDN);
  1894. //
  1895. // Reset this instance
  1896. //
  1897. _FreeMemberVariables();
  1898. return hr;
  1899. }
  1900. HRESULT CReplicaSet::_SetCustomTopologyPref()
  1901. {
  1902. HRESULT hr = put_TopologyPref(FRS_RSTOPOLOGYPREF_CUSTOM);
  1903. if (SUCCEEDED(hr))
  1904. hr = put_HubMemberDN(_T(""));
  1905. return hr;
  1906. }
  1907. HRESULT CReplicaSet::_AdjustConnectionsAdd(BSTR i_bstrNewMemberDN, BSTR i_bstrSite)
  1908. {
  1909. RETURN_INVALIDARG_IF_NULL(i_bstrNewMemberDN);
  1910. HRESULT hr = S_OK;
  1911. //
  1912. // adjust connections after pFrsMember is added
  1913. //
  1914. if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_CUSTOM) || m_frsMemberList.empty())
  1915. return hr;
  1916. if (m_frsMemberList.size() == 2)
  1917. {
  1918. CFrsMemberList::iterator head = m_frsMemberList.begin();
  1919. hr = AddConnection((*head)->m_bstrMemberDN, i_bstrNewMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1920. if (SUCCEEDED(hr))
  1921. hr = AddConnection(i_bstrNewMemberDN, (*head)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1922. return hr;
  1923. }
  1924. CFrsMemberList::iterator n1;
  1925. CFrsMemberList::iterator n2;
  1926. if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_RING))
  1927. {
  1928. CComBSTR bstrMemberDN1;
  1929. CComBSTR bstrMemberDN2;
  1930. CFrsConnectionList::iterator conn;
  1931. if (i_bstrSite && *i_bstrSite)
  1932. {
  1933. for (n1 = m_frsMemberList.begin(); n1 != m_frsMemberList.end(); n1++)
  1934. {
  1935. if (!lstrcmpi((*n1)->m_bstrSite, i_bstrSite) && // has the same site as the new member
  1936. lstrcmpi((*n1)->m_bstrMemberDN, i_bstrNewMemberDN)) // different from the new member
  1937. {
  1938. //
  1939. // see if there is an existing connection from/to this member n1
  1940. //
  1941. for (conn = m_frsConnectionList.begin(); conn != m_frsConnectionList.end(); conn++)
  1942. {
  1943. if (!lstrcmpi((*n1)->m_bstrMemberDN, (*conn)->m_bstrFromMemberDN))
  1944. {
  1945. bstrMemberDN1 = (*n1)->m_bstrMemberDN;
  1946. bstrMemberDN2 = (*conn)->m_bstrToMemberDN;
  1947. break;
  1948. } else if (!lstrcmpi((*n1)->m_bstrMemberDN, (*conn)->m_bstrToMemberDN))
  1949. {
  1950. bstrMemberDN1 = (*n1)->m_bstrMemberDN;
  1951. bstrMemberDN2 = (*conn)->m_bstrFromMemberDN;
  1952. break;
  1953. }
  1954. }
  1955. if ((BSTR)bstrMemberDN1 && (BSTR)bstrMemberDN2)
  1956. break; // we've located the insertion point
  1957. }
  1958. }
  1959. }
  1960. if (!bstrMemberDN1 || !bstrMemberDN2)
  1961. {
  1962. //
  1963. // locate an existing connection, if any
  1964. //
  1965. if (m_frsConnectionList.empty())
  1966. {
  1967. n1 = m_frsMemberList.begin();
  1968. n2 = n1++;
  1969. bstrMemberDN1 = (*n1)->m_bstrMemberDN;
  1970. bstrMemberDN2 = (*n2)->m_bstrMemberDN;
  1971. } else
  1972. {
  1973. conn = m_frsConnectionList.begin();
  1974. bstrMemberDN1 = (*conn)->m_bstrFromMemberDN;
  1975. bstrMemberDN2 = (*conn)->m_bstrToMemberDN;
  1976. }
  1977. }
  1978. hr = AddConnection(bstrMemberDN1, i_bstrNewMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1979. RETURN_IF_FAILED(hr);
  1980. hr = AddConnection(i_bstrNewMemberDN, bstrMemberDN1, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1981. RETURN_IF_FAILED(hr);
  1982. hr = AddConnection(bstrMemberDN2, i_bstrNewMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1983. RETURN_IF_FAILED(hr);
  1984. hr = AddConnection(i_bstrNewMemberDN, bstrMemberDN2, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1985. RETURN_IF_FAILED(hr);
  1986. if (m_frsMemberList.size() > 3)
  1987. {
  1988. hr = RemoveConnectionEx(bstrMemberDN2, bstrMemberDN1);
  1989. RETURN_IF_FAILED(hr);
  1990. hr = RemoveConnectionEx(bstrMemberDN1, bstrMemberDN2);
  1991. RETURN_IF_FAILED(hr);
  1992. }
  1993. } else if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE))
  1994. {
  1995. hr = AddConnection(i_bstrNewMemberDN, m_bstrHubMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1996. RETURN_IF_FAILED(hr);
  1997. hr = AddConnection(m_bstrHubMemberDN, i_bstrNewMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  1998. RETURN_IF_FAILED(hr);
  1999. } else if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_FULLMESH))
  2000. {
  2001. for (n1 = m_frsMemberList.begin(); n1 != m_frsMemberList.end(); n1++)
  2002. {
  2003. hr = AddConnection((*n1)->m_bstrMemberDN, i_bstrNewMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  2004. BREAK_IF_FAILED(hr);
  2005. hr = AddConnection(i_bstrNewMemberDN, (*n1)->m_bstrMemberDN, TRUE, FALSE, (long)PRIORITY_LOW, NULL);
  2006. BREAK_IF_FAILED(hr);
  2007. }
  2008. }
  2009. return hr;
  2010. }
  2011. /////////////////////////////////////////////////////////////////////////////////////////////////
  2012. // _FreeMemberVariables
  2013. void FreeDfsAlternates(CDfsAlternateList* pList)
  2014. {
  2015. if (pList && !pList->empty())
  2016. {
  2017. for (CDfsAlternateList::iterator i = pList->begin(); i != pList->end(); i++)
  2018. delete (*i);
  2019. pList->clear();
  2020. }
  2021. }
  2022. void FreeFrsMembers(CFrsMemberList* pList)
  2023. {
  2024. if (pList && !pList->empty())
  2025. {
  2026. for (CFrsMemberList::iterator i = pList->begin(); i != pList->end(); i++)
  2027. delete (*i);
  2028. pList->clear();
  2029. }
  2030. }
  2031. void FreeFrsConnections(CFrsConnectionList* pList)
  2032. {
  2033. if (pList && !pList->empty())
  2034. {
  2035. for (CFrsConnectionList::iterator i = pList->begin(); i != pList->end(); i++)
  2036. delete (*i);
  2037. pList->clear();
  2038. }
  2039. }
  2040. void CReplicaSet::_FreeMemberVariables()
  2041. {
  2042. m_bstrType.Empty();
  2043. m_bstrTopologyPref.Empty();
  2044. m_bstrHubMemberDN.Empty();
  2045. m_bstrPrimaryMemberDN.Empty();
  2046. m_bstrFileFilter.Empty();
  2047. m_bstrDirFilter.Empty();
  2048. m_bstrDfsEntryPath.Empty();
  2049. m_bstrReplicaSetDN.Empty();
  2050. FreeDfsAlternates(&m_dfsAlternateList);
  2051. FreeFrsMembers(&m_frsMemberList);
  2052. FreeFrsConnections(&m_frsConnectionList);
  2053. m_bstrDomain.Empty();
  2054. m_bstrDomainGuid.Empty();
  2055. m_bstrDC.Empty();
  2056. m_bNewSchema = FALSE;
  2057. if (m_pldap)
  2058. {
  2059. CloseConnectionToDS(m_pldap);
  2060. m_pldap = NULL;
  2061. }
  2062. }
  2063. ///////////////////////////////////////////////////////////////////
  2064. //
  2065. // CFrsMember
  2066. //
  2067. HRESULT CFrsMember::InitEx(
  2068. PLDAP i_pldap, // points to the i_bstrMemberDN's DS
  2069. BSTR i_bstrDC, // domain controller pointed by i_pldap
  2070. BSTR i_bstrMemberDN, // FQDN of nTFRSMember object
  2071. BSTR i_bstrComputerDN // =NULL, FQDN of computer object
  2072. )
  2073. {
  2074. _ReSet();
  2075. RETURN_INVALIDARG_IF_NULL(i_pldap);
  2076. RETURN_INVALIDARG_IF_NULL(i_bstrDC);
  2077. RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN);
  2078. HRESULT hr = S_OK;
  2079. do {
  2080. m_bstrMemberDN = i_bstrMemberDN;
  2081. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrMemberDN, &hr);
  2082. if (i_bstrComputerDN && *i_bstrComputerDN)
  2083. {
  2084. m_bstrComputerDN = i_bstrComputerDN;
  2085. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrComputerDN, &hr);
  2086. }
  2087. hr = _GetMemberInfo(i_pldap, i_bstrDC, m_bstrMemberDN, m_bstrComputerDN);
  2088. } while (0);
  2089. if (S_OK != hr)
  2090. _ReSet();
  2091. return hr;
  2092. }
  2093. HRESULT CFrsMember::Init(
  2094. IN BSTR i_bstrDnsHostName,
  2095. IN BSTR i_bstrComputerDomain,
  2096. IN BSTR i_bstrComputerGuid,
  2097. IN BSTR i_bstrRootPath,
  2098. IN BSTR i_bstrStagingPath,
  2099. IN BSTR i_bstrMemberDN,
  2100. IN BSTR i_bstrComputerDN,
  2101. IN BSTR i_bstrSubscriberDN
  2102. )
  2103. {
  2104. _ReSet();
  2105. RETURN_INVALIDARG_IF_NULL(i_bstrDnsHostName);
  2106. RETURN_INVALIDARG_IF_NULL(i_bstrComputerDomain);
  2107. RETURN_INVALIDARG_IF_NULL(i_bstrComputerGuid);
  2108. RETURN_INVALIDARG_IF_NULL(i_bstrRootPath);
  2109. RETURN_INVALIDARG_IF_NULL(i_bstrStagingPath);
  2110. RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN);
  2111. RETURN_INVALIDARG_IF_NULL(i_bstrComputerDN);
  2112. RETURN_INVALIDARG_IF_NULL(i_bstrSubscriberDN);
  2113. HRESULT hr = S_OK;
  2114. do {
  2115. hr = GetSiteName(i_bstrDnsHostName, &m_bstrSite);
  2116. BREAK_IF_FAILED(hr);
  2117. m_bstrServer = i_bstrDnsHostName;
  2118. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrServer, &hr);
  2119. m_bstrDomain = i_bstrComputerDomain;
  2120. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDomain, &hr);
  2121. m_bstrServerGuid = i_bstrComputerGuid;
  2122. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrServerGuid, &hr);
  2123. m_bstrRootPath = i_bstrRootPath;
  2124. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrRootPath, &hr);
  2125. m_bstrStagingPath = i_bstrStagingPath;
  2126. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrStagingPath, &hr);
  2127. m_bstrMemberDN = i_bstrMemberDN;
  2128. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrMemberDN, &hr);
  2129. m_bstrComputerDN = i_bstrComputerDN;
  2130. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrComputerDN, &hr);
  2131. m_bstrSubscriberDN = i_bstrSubscriberDN;
  2132. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrSubscriberDN, &hr);
  2133. } while (0);
  2134. if (FAILED(hr))
  2135. _ReSet();
  2136. return hr;
  2137. }
  2138. CFrsMember* CFrsMember::Copy()
  2139. {
  2140. CFrsMember* pNew = new CFrsMember;
  2141. if (pNew)
  2142. {
  2143. HRESULT hr = S_OK;
  2144. do {
  2145. pNew->m_bstrServer = m_bstrServer;
  2146. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrServer, &hr);
  2147. pNew->m_bstrSite = m_bstrSite;
  2148. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrSite, &hr);
  2149. pNew->m_bstrDomain = m_bstrDomain;
  2150. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrDomain, &hr);
  2151. pNew->m_bstrServerGuid = m_bstrServerGuid;
  2152. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrServerGuid, &hr);
  2153. pNew->m_bstrRootPath = m_bstrRootPath;
  2154. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrRootPath, &hr);
  2155. pNew->m_bstrStagingPath = m_bstrStagingPath;
  2156. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrStagingPath, &hr);
  2157. pNew->m_bstrMemberDN = m_bstrMemberDN;
  2158. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrMemberDN, &hr);
  2159. pNew->m_bstrComputerDN = m_bstrComputerDN;
  2160. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrComputerDN, &hr);
  2161. pNew->m_bstrSubscriberDN = m_bstrSubscriberDN;
  2162. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrSubscriberDN, &hr);
  2163. } while (0);
  2164. if (FAILED(hr))
  2165. {
  2166. delete pNew;
  2167. pNew = NULL;
  2168. }
  2169. }
  2170. return pNew;
  2171. }
  2172. void CFrsMember::_ReSet()
  2173. {
  2174. m_bstrServer.Empty();
  2175. m_bstrSite.Empty();
  2176. m_bstrDomain.Empty();
  2177. m_bstrServerGuid.Empty();
  2178. m_bstrRootPath.Empty();
  2179. m_bstrStagingPath.Empty();
  2180. m_bstrMemberDN.Empty();
  2181. m_bstrComputerDN.Empty();
  2182. m_bstrSubscriberDN.Empty();
  2183. }
  2184. //
  2185. // Given: MemberDN
  2186. // Read: ComputerDN, Domain, Site, ServerName
  2187. //
  2188. // Return:
  2189. // S_FALSE if no such object found
  2190. //
  2191. HRESULT CFrsMember::_GetMemberInfo
  2192. (
  2193. PLDAP i_pldap, // points to the i_bstrMemberDN's DS
  2194. BSTR i_bstrDC, // domain controller pointed by i_pldap
  2195. BSTR i_bstrMemberDN, // FQDN of nTFRSMember object
  2196. BSTR i_bstrComputerDN // = NULL FQDN of computer object
  2197. )
  2198. {
  2199. m_bstrDomain.Empty();
  2200. RETURN_INVALIDARG_IF_NULL(i_pldap);
  2201. RETURN_INVALIDARG_IF_NULL(i_bstrDC);
  2202. RETURN_INVALIDARG_IF_NULL(*i_bstrDC);
  2203. RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN);
  2204. RETURN_INVALIDARG_IF_NULL(*i_bstrMemberDN);
  2205. HRESULT hr = S_OK;
  2206. do {
  2207. if (!i_bstrComputerDN || !*i_bstrComputerDN)
  2208. {
  2209. m_bstrComputerDN.Empty();
  2210. //
  2211. // Read:
  2212. // m_bstrComputerDN
  2213. //
  2214. PLDAP_ATTR_VALUE pValues[2] = {0,0};
  2215. LDAP_ATTR_VALUE pAttributes[1];
  2216. pAttributes[0].bstrAttribute = ATTR_FRS_MEMBER_COMPUTERREF;
  2217. hr = GetValues( i_pldap,
  2218. m_bstrMemberDN,
  2219. OBJCLASS_SF_NTFRSMEMBER,
  2220. LDAP_SCOPE_BASE,
  2221. 1,
  2222. pAttributes,
  2223. pValues);
  2224. BREAK_IF_FAILED(hr);
  2225. hr = E_FAIL;
  2226. if (pValues[0])
  2227. {
  2228. m_bstrComputerDN = (PTSTR)(pValues[0]->vpValue);
  2229. hr = (!m_bstrComputerDN) ? E_OUTOFMEMORY : S_OK;
  2230. FreeAttrValList(pValues[0]);
  2231. }
  2232. BREAK_IF_FAILED(hr);
  2233. }
  2234. //
  2235. // retrieve the domain for both ComputerDN and i_bstrMemberDN
  2236. // If they are the same, reuse the handle to the LDAP port;
  2237. // otherwise, open a new handle.
  2238. //
  2239. // Read:
  2240. // m_bstrDomainDN
  2241. //
  2242. BOOL bSameDomain = FALSE;
  2243. HANDLE hDS = NULL;
  2244. DWORD dwErr = DsBind(i_bstrDC, NULL, &hDS);
  2245. if (NO_ERROR != dwErr)
  2246. {
  2247. hr = HRESULT_FROM_WIN32(dwErr);
  2248. break;
  2249. }
  2250. const PTSTR pszFQDNs[2] = {(BSTR)m_bstrComputerDN, i_bstrMemberDN};
  2251. DS_NAME_RESULT* pDsNameResult = NULL;
  2252. dwErr = DsCrackNames(
  2253. hDS,
  2254. DS_NAME_NO_FLAGS,
  2255. DS_FQDN_1779_NAME,
  2256. DS_CANONICAL_NAME,
  2257. 2,
  2258. pszFQDNs,
  2259. &pDsNameResult
  2260. );
  2261. if (NO_ERROR == dwErr)
  2262. {
  2263. do {
  2264. PDS_NAME_RESULT_ITEM pItem = pDsNameResult->rItems;
  2265. if (DS_NAME_NO_ERROR != pItem->status)
  2266. {
  2267. dwErr = pItem->status;
  2268. } else
  2269. {
  2270. // retrieve info of m_bstrComputerDN
  2271. m_bstrDomain = pItem->pDomain;
  2272. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDomain, &hr);
  2273. // retrieve info of i_bstrMemberDN
  2274. pItem++;
  2275. if (DS_NAME_NO_ERROR != pItem->status)
  2276. {
  2277. dwErr = pItem->status;
  2278. } else
  2279. {
  2280. bSameDomain = !mylstrncmpi(m_bstrDomain, pItem->pDomain, lstrlen(m_bstrDomain));
  2281. }
  2282. }
  2283. } while (0);
  2284. DsFreeNameResult(pDsNameResult);
  2285. }
  2286. DsUnBind(&hDS);
  2287. if (NO_ERROR != dwErr)
  2288. {
  2289. hr = HRESULT_FROM_WIN32(dwErr);
  2290. break;
  2291. }
  2292. //
  2293. // Create a new ldap handle if not in the same domain
  2294. //
  2295. PLDAP pldapComputer = NULL;
  2296. if (bSameDomain)
  2297. pldapComputer = i_pldap;
  2298. else
  2299. {
  2300. hr = ConnectToDS(m_bstrDomain, &pldapComputer);
  2301. BREAK_IF_FAILED(hr);
  2302. }
  2303. //
  2304. // Read:
  2305. // m_bstrSubscriberDN, m_bstrRootPath, m_bstrStagingPath
  2306. //
  2307. hr = _GetSubscriberInfo(pldapComputer, m_bstrComputerDN, i_bstrMemberDN);
  2308. //
  2309. // Read:
  2310. // m_bstrServer, m_bstrServerGuid, m_bstrSite
  2311. //
  2312. if (S_OK == hr)
  2313. hr = _GetComputerInfo(pldapComputer, m_bstrComputerDN);
  2314. //
  2315. // Close the newly created ldap handle
  2316. //
  2317. if (!bSameDomain)
  2318. CloseConnectionToDS(pldapComputer);
  2319. } while (0);
  2320. if (S_OK != hr)
  2321. {
  2322. if (!i_bstrComputerDN || !*i_bstrComputerDN)
  2323. m_bstrComputerDN.Empty();
  2324. m_bstrDomain.Empty();
  2325. }
  2326. return hr;
  2327. }
  2328. //
  2329. // Given: ComputerDN, MemberDN
  2330. // Read:
  2331. // m_bstrSubscriberDN, m_bstrRootPath, m_bstrStagingPath
  2332. //
  2333. // Return:
  2334. // S_FALSE if no such object found
  2335. //
  2336. HRESULT CFrsMember::_GetSubscriberInfo
  2337. (
  2338. PLDAP i_pldap, // points to the i_bstrComputerDN's DS
  2339. BSTR i_bstrComputerDN, // FQDN of the computer object
  2340. BSTR i_bstrMemberDN // FQDN of the corresponding nTFRSMember object
  2341. )
  2342. {
  2343. m_bstrSubscriberDN.Empty();
  2344. m_bstrRootPath.Empty();
  2345. m_bstrStagingPath.Empty();
  2346. RETURN_INVALIDARG_IF_NULL(i_pldap);
  2347. RETURN_INVALIDARG_IF_NULL(i_bstrComputerDN);
  2348. RETURN_INVALIDARG_IF_NULL(*i_bstrComputerDN);
  2349. RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN);
  2350. RETURN_INVALIDARG_IF_NULL(*i_bstrMemberDN);
  2351. //
  2352. // locate the nTFRSSubscriber object whose attribute "frsMemberReference"
  2353. // matches i_bstrMemberDN
  2354. //
  2355. CComBSTR bstrSearchFilter = _T("(&(objectCategory=nTFRSSubscriber)(frsMemberReference=");
  2356. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrSearchFilter);
  2357. bstrSearchFilter += i_bstrMemberDN;
  2358. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrSearchFilter);
  2359. bstrSearchFilter += _T("))");
  2360. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrSearchFilter);
  2361. PCTSTR ppszAttributes[] = {
  2362. ATTR_DISTINGUISHEDNAME,
  2363. ATTR_FRS_SUBSCRIBER_ROOTPATH,
  2364. ATTR_FRS_SUBSCRIBER_STAGINGPATH,
  2365. 0
  2366. };
  2367. LListElem* pElem = NULL;
  2368. HRESULT hr = GetValuesEx(
  2369. i_pldap,
  2370. i_bstrComputerDN,
  2371. LDAP_SCOPE_SUBTREE,
  2372. bstrSearchFilter,
  2373. ppszAttributes,
  2374. &pElem);
  2375. RETURN_IF_FAILED(hr);
  2376. if (!pElem) // no matching nTFRSSubscriber object
  2377. return S_FALSE;
  2378. LListElem* pCurElem = pElem;
  2379. while (pCurElem)
  2380. {
  2381. PTSTR** pppszValues = pCurElem->pppszAttrValues;
  2382. if (!pppszValues ||
  2383. !pppszValues[0] || !*(pppszValues[0]) ||
  2384. !pppszValues[1] || !*(pppszValues[1]) ||
  2385. !pppszValues[2] || !*(pppszValues[2]))
  2386. {
  2387. pCurElem = pCurElem->Next;
  2388. continue; // corrupted subscriber object
  2389. }
  2390. m_bstrSubscriberDN = *(pppszValues[0]);
  2391. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrSubscriberDN, &hr);
  2392. m_bstrRootPath = *(pppszValues[1]);
  2393. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrRootPath, &hr);
  2394. m_bstrStagingPath = *(pppszValues[2]);
  2395. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrStagingPath, &hr);
  2396. pCurElem = pCurElem->Next;
  2397. }
  2398. FreeLListElem(pElem);
  2399. if (FAILED(hr))
  2400. {
  2401. m_bstrSubscriberDN.Empty();
  2402. m_bstrRootPath.Empty();
  2403. m_bstrStagingPath.Empty();
  2404. }
  2405. return hr;
  2406. }
  2407. //
  2408. // Given: ComputerDN
  2409. // Read: m_bstrServer, m_bstrServerGuid, m_bstrSite
  2410. //
  2411. HRESULT CFrsMember::_GetComputerInfo
  2412. (
  2413. PLDAP i_pldap, // points to the i_bstrComputerDN's DS
  2414. BSTR i_bstrComputerDN // FQDN of the computer object
  2415. )
  2416. {
  2417. m_bstrServer.Empty();
  2418. m_bstrServerGuid.Empty();
  2419. m_bstrSite.Empty();
  2420. RETURN_INVALIDARG_IF_NULL(i_pldap);
  2421. RETURN_INVALIDARG_IF_NULL(i_bstrComputerDN);
  2422. RETURN_INVALIDARG_IF_NULL(*i_bstrComputerDN);
  2423. HRESULT hr = S_OK;
  2424. do {
  2425. //
  2426. // read dNSHostName and objectGUID on the ComputerDN
  2427. //
  2428. PLDAP_ATTR_VALUE pValues[3] = {0,0,0};
  2429. LDAP_ATTR_VALUE pAttributes[2];
  2430. pAttributes[0].bstrAttribute = ATTR_DNSHOSTNAME;
  2431. pAttributes[1].bstrAttribute = ATTR_OBJECTGUID;
  2432. pAttributes[1].bBerValue = true;
  2433. hr = GetValues( i_pldap,
  2434. i_bstrComputerDN,
  2435. OBJCLASS_SF_COMPUTER,
  2436. LDAP_SCOPE_BASE,
  2437. 2,
  2438. pAttributes,
  2439. pValues);
  2440. BREAK_IF_FAILED(hr);
  2441. hr = E_FAIL;
  2442. if (pValues[0])
  2443. {
  2444. m_bstrServer = (PTSTR)(pValues[0]->vpValue);
  2445. hr = (!m_bstrServer) ? E_OUTOFMEMORY : S_OK;
  2446. FreeAttrValList(pValues[0]);
  2447. }
  2448. if (pValues[1])
  2449. {
  2450. if (SUCCEEDED(hr))
  2451. {
  2452. if (pValues[1]->bBerValue)
  2453. {
  2454. hr = UuidToStructuredString((UUID*)(pValues[1]->vpValue), &m_bstrServerGuid);
  2455. } else
  2456. {
  2457. m_bstrServerGuid = (PTSTR)(pValues[1]->vpValue);
  2458. hr = (!m_bstrServerGuid) ? E_OUTOFMEMORY : S_OK;
  2459. }
  2460. }
  2461. FreeAttrValList(pValues[1]);
  2462. }
  2463. BREAK_IF_FAILED(hr);
  2464. //
  2465. // retrieve Site
  2466. //
  2467. hr = GetSiteName(m_bstrServer, &m_bstrSite);
  2468. BREAK_IF_FAILED(hr);
  2469. } while (0);
  2470. if (FAILED(hr))
  2471. {
  2472. m_bstrServer.Empty();
  2473. m_bstrServerGuid.Empty();
  2474. m_bstrSite.Empty();
  2475. }
  2476. return hr;
  2477. }
  2478. //////////////////////////////////////////////////////////
  2479. //
  2480. // CFrsConnection
  2481. //
  2482. HRESULT CFrsConnection::Init(
  2483. BSTR i_bstrConnectionDN,
  2484. BSTR i_bstrFromMemberDN,
  2485. BOOL i_bEnable,
  2486. DWORD i_dwOptions)
  2487. {
  2488. _ReSet();
  2489. RETURN_INVALIDARG_IF_NULL(i_bstrConnectionDN);
  2490. RETURN_INVALIDARG_IF_NULL(i_bstrFromMemberDN);
  2491. HRESULT hr = S_OK;
  2492. do {
  2493. m_bstrConnectionDN = i_bstrConnectionDN;
  2494. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrConnectionDN, &hr);
  2495. m_bstrFromMemberDN = i_bstrFromMemberDN;
  2496. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromMemberDN, &hr);
  2497. TCHAR* p = _tcschr(m_bstrConnectionDN, _T(','));
  2498. if (!p)
  2499. {
  2500. hr = E_INVALIDARG;
  2501. break;
  2502. }
  2503. m_bstrToMemberDN = p + 1;
  2504. BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToMemberDN, &hr);
  2505. m_bEnable = i_bEnable;
  2506. m_dwOptions = i_dwOptions;
  2507. } while (0);
  2508. if (FAILED(hr))
  2509. _ReSet();
  2510. return hr;
  2511. }
  2512. CFrsConnection* CFrsConnection::Copy()
  2513. {
  2514. CFrsConnection* pNew = new CFrsConnection;
  2515. if (pNew)
  2516. {
  2517. HRESULT hr = S_OK;
  2518. do {
  2519. pNew->m_bstrConnectionDN = m_bstrConnectionDN;
  2520. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrConnectionDN, &hr);
  2521. pNew->m_bstrFromMemberDN = m_bstrFromMemberDN;
  2522. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrFromMemberDN, &hr);
  2523. pNew->m_bstrToMemberDN = m_bstrToMemberDN;
  2524. BREAK_OUTOFMEMORY_IF_NULL((BSTR)pNew->m_bstrToMemberDN, &hr);
  2525. pNew->m_bEnable = m_bEnable;
  2526. pNew->m_dwOptions = m_dwOptions;
  2527. } while (0);
  2528. if (FAILED(hr))
  2529. {
  2530. delete pNew;
  2531. pNew = NULL;
  2532. }
  2533. }
  2534. return pNew;
  2535. }
  2536. void CFrsConnection::_ReSet()
  2537. {
  2538. m_bstrConnectionDN.Empty();
  2539. m_bstrFromMemberDN.Empty();
  2540. m_bstrToMemberDN.Empty();
  2541. m_bEnable = TRUE;
  2542. m_dwOptions = 0;
  2543. }