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.

4780 lines
156 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <winldap.h>
  5. #include <ntldap.h>
  6. #include <schedule.h>
  7. #include <mkdso.h>
  8. #include <frsrpc.h>
  9. #include <ntdsapi.h>
  10. #include <winber.h>
  11. #define ArgMatch(_a, _b) (wcsstr(_a, _b) == (_a))
  12. #define WCS_CAT7(_dest, _a1, _a2, _a3, _a4, _a5, _a6, _a7 ) \
  13. wcscpy(_dest, _a1); \
  14. wcscat(_dest, _a2); \
  15. wcscat(_dest, _a3); \
  16. wcscat(_dest, _a4); \
  17. wcscat(_dest, _a5); \
  18. wcscat(_dest, _a6); \
  19. wcscat(_dest, _a7);
  20. //
  21. // Some useful ldap macroes
  22. //
  23. #define LDAP_FREE_MSG(x) {if (x) {ldap_msgfree(x); (x) = NULL;}}
  24. #define LDAP_FREE_VALUES(x) {if (x) {ldap_value_free(x); (x) = NULL;}}
  25. #define LDAP_FREE_BER_VALUES(x) {if (x) {ldap_value_free_len(x); (x) = NULL;}}
  26. //Global data
  27. BOOL bVerboseMode = FALSE;
  28. BOOL bVerboseModeSearch = FALSE;
  29. PWCHAR DcName = NULL;
  30. PLDAP pLdap = NULL;
  31. BOOL bDebugMode = FALSE;
  32. BOOL bAffectAll = FALSE;
  33. PBYTE SchedMask = NULL;
  34. PBYTE SchedOverride = NULL;
  35. BOOL bCreateSet = FALSE;
  36. BOOL bUpdateSet = FALSE;
  37. BOOL bDelSet = FALSE;
  38. BOOL bCreateMember = FALSE;
  39. BOOL bMakeMePrimary = FALSE;
  40. BOOL bUpdateMember = FALSE;
  41. BOOL bDelMember = FALSE;
  42. BOOL bCreateSubscriber = FALSE;
  43. BOOL bUpdateSubscriber = FALSE;
  44. BOOL bDelSubscriber = FALSE;
  45. BOOL bDump = FALSE;
  46. BOOL bSchedule = FALSE;
  47. BOOL bDFSNaming = FALSE;
  48. WCHAR ComputerObjectGuidStr[50];
  49. PWCHAR DomainGuidStr = NULL; // [50];
  50. PWCHAR DFSName = NULL;
  51. //
  52. // Static array to print the replica set type.
  53. //
  54. WCHAR ReplicaSetTypeStr[][MAX_PATH] = {L"Invalid type",
  55. L"Invalid type",
  56. L"Sysvol",
  57. L"Dfs",
  58. L"Other"};
  59. DWORD
  60. UpdateReplicaSet(
  61. PWCHAR NTFRSSettingsDn,
  62. PWCHAR ReplicaSetName,
  63. PWCHAR ReplicaSetType,
  64. PWCHAR FileFilter,
  65. PWCHAR DirectoryFilter,
  66. PWCHAR PrimaryMember,
  67. PBYTE pSchedule
  68. );
  69. VOID
  70. PrintScheduleGrid(
  71. PUCHAR ScheduleData,
  72. DWORD Mask
  73. );
  74. VOID
  75. PrintSchedule(
  76. PSCHEDULE Schedule,
  77. DWORD Mask
  78. );
  79. DWORD
  80. BindToDC (
  81. IN PWCHAR pszDC,
  82. OUT PLDAP *ppLDAP
  83. )
  84. /*++
  85. Routine Description:
  86. Sets up an LDAP connection to the specified server
  87. Arguments:
  88. pwszDC - DS DC to bind to
  89. ppLDAP - The LDAP connection information is returned here
  90. Return Value:
  91. ERROR_SUCCESS - Success
  92. --*/
  93. {
  94. DWORD dwErr = ERROR_SUCCESS;
  95. ULONG ulOptions;
  96. //
  97. // if ldap_open is called with a server name the api will call DsGetDcName
  98. // passing the server name as the domainname parm...bad, because
  99. // DsGetDcName will make a load of DNS queries based on the server name,
  100. // it is designed to construct these queries from a domain name...so all
  101. // these queries will be bogus, meaning they will waste network bandwidth,
  102. // time to fail, and worst case cause expensive on demand links to come up
  103. // as referrals/forwarders are contacted to attempt to resolve the bogus
  104. // names. By setting LDAP_OPT_AREC_EXCLUSIVE to on using ldap_set_option
  105. // after the ldap_init but before any other operation using the ldap
  106. // handle from ldap_init, the delayed connection setup will not call
  107. // DsGetDcName, just gethostbyname, or if an IP is passed, the ldap client
  108. // will detect that and use the address directly.
  109. //
  110. // *ppLDAP = ldap_open(pszDC, LDAP_PORT);
  111. *ppLDAP = ldap_init(pszDC, LDAP_PORT);
  112. if(*ppLDAP == NULL) {
  113. dwErr = ERROR_PATH_NOT_FOUND;
  114. } else {
  115. //
  116. // set the options.
  117. //
  118. ulOptions = PtrToUlong(LDAP_OPT_ON);
  119. ldap_set_option(*ppLDAP, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  120. //
  121. // Do a bind...
  122. //
  123. dwErr = ldap_bind_s(*ppLDAP, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  124. }
  125. return(dwErr);
  126. }
  127. PWCHAR
  128. FrsWcsDup(
  129. PWCHAR OldStr
  130. )
  131. /*++
  132. Routine Description:
  133. Duplicate a string using our memory allocater
  134. Arguments:
  135. OldArg - string to duplicate
  136. Return Value:
  137. Duplicated string. Free with FrsFree().
  138. --*/
  139. {
  140. PWCHAR NewStr;
  141. //
  142. // E.g., when duplicating NodePartner when none exists
  143. //
  144. if (OldStr == NULL)
  145. return NULL;
  146. NewStr = (PWCHAR)malloc((wcslen(OldStr) + 1) * sizeof(WCHAR));
  147. wcscpy(NewStr, OldStr);
  148. return NewStr;
  149. }
  150. VOID
  151. AddMod(
  152. PWCHAR AttrType,
  153. PWCHAR AttrValue,
  154. LDAPMod ***pppMod
  155. )
  156. /*++
  157. Routine Description:
  158. Add an attribute (plus values) to a structure that will eventually be
  159. used in an ldap_add() function to add an object to the DS. The null-
  160. terminated array referenced by pppMod grows with each call to this
  161. routine. The array is freed by the caller using FreeMod().
  162. Arguments:
  163. AttrType - The object class of the object.
  164. AttrValue - The value of the attribute.
  165. pppMod - Address of an array of pointers to "attributes". Don't
  166. give me that look -- this is an LDAP thing.
  167. Return Value:
  168. The pppMod array grows by one entry. The caller must free it with
  169. FreeMod().
  170. --*/
  171. {
  172. DWORD NumMod; // Number of entries in the Mod array
  173. LDAPMod **ppMod; // Address of the first entry in the Mod array
  174. LDAPMod *Attr; // An attribute structure
  175. PWCHAR *Values; // An array of pointers to bervals
  176. if (AttrValue == NULL)
  177. return;
  178. //
  179. // The null-terminated array doesn't exist; create it
  180. //
  181. if (*pppMod == NULL) {
  182. *pppMod = (LDAPMod **)malloc(sizeof (*pppMod));
  183. **pppMod = NULL;
  184. }
  185. //
  186. // Increase the array's size by 1
  187. //
  188. for (ppMod = *pppMod, NumMod = 2; *ppMod != NULL; ++ppMod, ++NumMod);
  189. *pppMod = (LDAPMod **)realloc(*pppMod, sizeof (*pppMod) * NumMod);
  190. //
  191. // Add the new attribute + value to the Mod array
  192. //
  193. Values = (PWCHAR *)malloc(sizeof (PWCHAR) * 2);
  194. Values[0] = _wcsdup(AttrValue);
  195. Values[1] = NULL;
  196. Attr = (LDAPMod *)malloc(sizeof (*Attr));
  197. Attr->mod_values = Values;
  198. Attr->mod_type = _wcsdup(AttrType);
  199. // Attr->mod_op = LDAP_MOD_ADD;
  200. Attr->mod_op = LDAP_MOD_REPLACE;
  201. (*pppMod)[NumMod - 1] = NULL;
  202. (*pppMod)[NumMod - 2] = Attr;
  203. }
  204. VOID
  205. AddBerMod(
  206. PWCHAR AttrType,
  207. PCHAR AttrValue,
  208. DWORD AttrValueLen,
  209. LDAPMod ***pppMod
  210. )
  211. /*++
  212. Routine Description:
  213. Add an attribute (plus values) to a structure that will eventually be
  214. used in an ldap_add() function to add an object to the DS. The null-
  215. terminated array referenced by pppMod grows with each call to this
  216. routine. The array is freed by the caller using FreeMod().
  217. Arguments:
  218. AttrType - The object class of the object.
  219. AttrValue - The value of the attribute.
  220. AttrValueLen - length of the attribute
  221. pppMod - Address of an array of pointers to "attributes". Don't
  222. give me that look -- this is an LDAP thing.
  223. Return Value:
  224. The pppMod array grows by one entry. The caller must free it with
  225. FreeMod().
  226. --*/
  227. {
  228. DWORD NumMod; // Number of entries in the Mod array
  229. LDAPMod **ppMod; // Address of the first entry in the Mod array
  230. LDAPMod *Attr; // An attribute structure
  231. PLDAP_BERVAL Berval;
  232. PLDAP_BERVAL *Values; // An array of pointers to bervals
  233. if (AttrValue == NULL) {
  234. return;
  235. }
  236. //
  237. // The null-terminated array doesn't exist; create it
  238. //
  239. if (*pppMod == NULL) {
  240. *pppMod = (LDAPMod **)malloc(sizeof (*pppMod));
  241. **pppMod = NULL;
  242. }
  243. //
  244. // Increase the array's size by 1
  245. //
  246. for (ppMod = *pppMod, NumMod = 2; *ppMod != NULL; ++ppMod, ++NumMod);
  247. *pppMod = (LDAPMod **)realloc(*pppMod, sizeof (*pppMod) * NumMod);
  248. //
  249. // Construct a berval
  250. //
  251. Berval = (PLDAP_BERVAL)malloc(sizeof(LDAP_BERVAL));
  252. Berval->bv_len = AttrValueLen;
  253. Berval->bv_val = (PCHAR)malloc(AttrValueLen);
  254. CopyMemory(Berval->bv_val, AttrValue, AttrValueLen);
  255. //
  256. // Add the new attribute + value to the Mod array
  257. //
  258. Values = (PLDAP_BERVAL *)malloc(sizeof (PLDAP_BERVAL) * 2);
  259. Values[0] = Berval;
  260. Values[1] = NULL;
  261. Attr = (LDAPMod *)malloc(sizeof (*Attr));
  262. Attr->mod_bvalues = Values;
  263. Attr->mod_type = _wcsdup(AttrType);
  264. Attr->mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE;
  265. (*pppMod)[NumMod - 1] = NULL;
  266. (*pppMod)[NumMod - 2] = Attr;
  267. }
  268. VOID
  269. FreeMod(
  270. LDAPMod ***pppMod
  271. )
  272. /*++
  273. Routine Description:
  274. Free the structure built by successive calls to AddMod().
  275. Arguments:
  276. pppMod - Address of a null-terminated array.
  277. Return Value:
  278. *pppMod set to NULL.
  279. --*/
  280. {
  281. DWORD i, j;
  282. LDAPMod **ppMod;
  283. if (!pppMod || !*pppMod) {
  284. return;
  285. }
  286. //
  287. // For each attibute
  288. //
  289. ppMod = *pppMod;
  290. for (i = 0; ppMod[i] != NULL; ++i) {
  291. //
  292. // For each value of the attribute
  293. //
  294. for (j = 0; (ppMod[i])->mod_values[j] != NULL; ++j) {
  295. //
  296. // Free the value
  297. //
  298. if (ppMod[i]->mod_op & LDAP_MOD_BVALUES) {
  299. free(ppMod[i]->mod_bvalues[j]->bv_val);
  300. }
  301. free((ppMod[i])->mod_values[j]);
  302. }
  303. free((ppMod[i])->mod_values); // Free the array of pointers to values
  304. free((ppMod[i])->mod_type); // Free the string identifying the attribute
  305. free(ppMod[i]); // Free the attribute
  306. }
  307. free(ppMod); // Free the array of pointers to attributes
  308. *pppMod = NULL; // Now ready for more calls to AddMod()
  309. }
  310. BOOL
  311. LdapSearch(
  312. PLDAP ldap,
  313. PWCHAR Base,
  314. ULONG Scope,
  315. PWCHAR Filter,
  316. PWCHAR Attrs[],
  317. ULONG AttrsOnly,
  318. LDAPMessage **Res,
  319. BOOL Quiet
  320. )
  321. /*++
  322. Routine Description:
  323. Issue the ldap ldap_search_s call, check for errors, and check for
  324. a shutdown in progress.
  325. Arguments:
  326. ldap
  327. Base
  328. Scope
  329. Filter
  330. Attrs
  331. AttrsOnly
  332. Res
  333. Return Value:
  334. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  335. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  336. --*/
  337. {
  338. DWORD LStatus;
  339. //
  340. // Issue the ldap search
  341. //
  342. LStatus = ldap_search_s(ldap, Base, Scope, Filter, Attrs, AttrsOnly, Res);
  343. //
  344. // Check for errors
  345. //
  346. if (LStatus != LDAP_SUCCESS) {
  347. if (!Quiet) {
  348. DPRINT4("WARN - Error searching %ws for %ws; LStatus %d: %ws\n",
  349. Base, Filter, LStatus, ldap_err2string(LStatus));
  350. }
  351. return FALSE;
  352. }
  353. //
  354. // Return TRUE if not shutting down
  355. //
  356. return TRUE;
  357. }
  358. PWCHAR *
  359. GetValues(
  360. IN PLDAP Ldap,
  361. IN PWCHAR Dn,
  362. IN PWCHAR DesiredAttr,
  363. IN BOOL Quiet
  364. )
  365. /*++
  366. Routine Description:
  367. Return the DS values for one attribute in an object.
  368. Arguments:
  369. ldap - An open, bound ldap port.
  370. Base - The "pathname" of a DS object.
  371. DesiredAttr - Return values for this attribute.
  372. Quiet
  373. Return Value:
  374. An array of char pointers that represents the values for the attribute.
  375. The caller must free the array with LDAP_FREE_VALUES(). NULL if unsuccessful.
  376. --*/
  377. {
  378. PWCHAR Attr;
  379. BerElement *Ber;
  380. PLDAPMessage LdapMsg;
  381. PLDAPMessage LdapEntry;
  382. PWCHAR Attrs[2];
  383. PWCHAR *Values = NULL;
  384. //
  385. // Search Base for all of its attributes + values
  386. //
  387. MK_ATTRS_1(Attrs, DesiredAttr);
  388. //
  389. // Issue the ldap search
  390. //
  391. if (!LdapSearch(Ldap, Dn, LDAP_SCOPE_BASE, CLASS_ANY, Attrs, 0, &LdapMsg, Quiet)) {
  392. return NULL;
  393. }
  394. LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  395. if (LdapEntry) {
  396. Attr = ldap_first_attribute(Ldap, LdapEntry, &Ber);
  397. if (Attr) {
  398. Values = ldap_get_values(Ldap, LdapEntry, Attr);
  399. }
  400. }
  401. LDAP_FREE_MSG(LdapMsg);
  402. return Values;
  403. }
  404. PLDAP_BERVAL *
  405. GetBerValues(
  406. IN PLDAP Ldap,
  407. IN PWCHAR Dn,
  408. IN PWCHAR DesiredAttr,
  409. IN BOOL Quiet
  410. )
  411. /*++
  412. Routine Description:
  413. Return the DS Ber values for one binary attribute in an object.
  414. Arguments:
  415. ldap - An open, bound ldap port.
  416. Base - The "pathname" of a DS object.
  417. DesiredAttr - Return values for this attribute.
  418. Quiet
  419. Return Value:
  420. An array of BerVal struct pointers that represents the values for the attribute.
  421. The caller must free the array with LDAP_FREE_BER_VALUES(). NULL if unsuccessful.
  422. --*/
  423. {
  424. PWCHAR Attr;
  425. BerElement *Ber;
  426. PLDAPMessage LdapMsg;
  427. PLDAPMessage LdapEntry;
  428. PWCHAR Attrs[2];
  429. PLDAP_BERVAL *Values = NULL;
  430. //
  431. // Search Base for all of its attributes + values
  432. //
  433. MK_ATTRS_1(Attrs, DesiredAttr);
  434. //
  435. // Issue the ldap search
  436. //
  437. if (!LdapSearch(Ldap, Dn, LDAP_SCOPE_BASE, CLASS_ANY, Attrs, 0, &LdapMsg, Quiet)) {
  438. return NULL;
  439. }
  440. LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  441. if (LdapEntry) {
  442. Attr = ldap_first_attribute(Ldap, LdapEntry, &Ber);
  443. if (Attr) {
  444. Values = ldap_get_values_len(Ldap, LdapEntry, Attr);
  445. }
  446. }
  447. LDAP_FREE_MSG(LdapMsg);
  448. return Values;
  449. }
  450. BOOL
  451. LdapSearchInit(
  452. PLDAP ldap,
  453. PWCHAR Base,
  454. ULONG Scope,
  455. PWCHAR Filter,
  456. PWCHAR Attrs[],
  457. ULONG AttrsOnly,
  458. PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext,
  459. BOOL Quiet
  460. )
  461. /*++
  462. Routine Description:
  463. Issue the ldap ldap_search_s call, check for errors, and check for
  464. a shutdown in progress.
  465. Arguments:
  466. ldap
  467. Base
  468. Scope
  469. Filter
  470. Attrs
  471. AttrsOnly
  472. Res
  473. FrsSearchContext
  474. Return Value:
  475. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  476. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  477. --*/
  478. {
  479. DWORD LStatus = LDAP_SUCCESS;
  480. PLDAPControl ServerControls[2];
  481. berval cookie1 = { 0, NULL };
  482. FrsSearchContext->bOpen = FALSE;
  483. FrsSearchContext->LdapMsg = NULL;
  484. FrsSearchContext->EntriesInPage = 0;
  485. FrsSearchContext->CurrentEntry = 0;
  486. FrsSearchContext->TotalEntries = 0;
  487. FrsSearchContext->Filter = FrsWcsDup(Filter);
  488. FrsSearchContext->BaseDn = FrsWcsDup(Base);
  489. FrsSearchContext->Scope = Scope;
  490. FrsSearchContext->PageSize = FRS_LDAP_SEARCH_PAGESIZE;
  491. FrsSearchContext->Attrs = Attrs;
  492. LStatus = ldap_create_page_control(ldap,
  493. FrsSearchContext->PageSize,
  494. &cookie1,
  495. FALSE, // is critical
  496. &ServerControls[0]
  497. );
  498. ServerControls[1] = NULL;
  499. if (LStatus != LDAP_SUCCESS) {
  500. DPRINT1("ldap_create_page_control returned error. LStatus = 0x%x\n", LStatus);
  501. }
  502. LStatus = ldap_search_ext_s(ldap,
  503. FrsSearchContext->BaseDn,
  504. FrsSearchContext->Scope,
  505. FrsSearchContext->Filter,
  506. FrsSearchContext->Attrs,
  507. FALSE,
  508. ServerControls,
  509. NULL,
  510. NULL,
  511. 0,
  512. &FrsSearchContext->LdapMsg);
  513. if (LStatus == LDAP_SUCCESS) {
  514. FrsSearchContext->EntriesInPage = ldap_count_entries(ldap, FrsSearchContext->LdapMsg);
  515. FrsSearchContext->CurrentEntry = 0;
  516. FrsSearchContext->bOpen = TRUE;
  517. }
  518. return (LStatus == LDAP_SUCCESS);
  519. }
  520. PLDAPMessage
  521. LdapSearchGetNextEntry(
  522. PLDAP ldap,
  523. PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
  524. )
  525. /*++
  526. Routine Description:
  527. Issue the ldap ldap_search_s call, check for errors, and check for
  528. a shutdown in progress.
  529. Arguments:
  530. ldap
  531. FrsSearchContext
  532. Return Value:
  533. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  534. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  535. --*/
  536. {
  537. FrsSearchContext->CurrentEntry += 1;
  538. if ( FrsSearchContext->CurrentEntry == 1 ) {
  539. FrsSearchContext->CurrentLdapMsg = ldap_first_entry(ldap ,FrsSearchContext->LdapMsg);
  540. } else {
  541. FrsSearchContext->CurrentLdapMsg = ldap_next_entry(ldap ,FrsSearchContext->CurrentLdapMsg);
  542. }
  543. return FrsSearchContext->CurrentLdapMsg;
  544. }
  545. DWORD
  546. LdapSearchGetNextPage(
  547. PLDAP ldap,
  548. PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
  549. )
  550. /*++
  551. Routine Description:
  552. Issue the ldap ldap_search_s call, check for errors, and check for
  553. a shutdown in progress.
  554. Arguments:
  555. ldap
  556. FrsSearchContext
  557. Return Value:
  558. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  559. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  560. --*/
  561. {
  562. DWORD LStatus = LDAP_SUCCESS;
  563. berval * CurrCookie = NULL;
  564. PLDAPControl * CurrControls = NULL;
  565. ULONG retcode = 0;
  566. PLDAPControl ServerControls[2];
  567. // Get the server control from the message, and make a new control with the cookie from the server
  568. LStatus = ldap_parse_result(ldap, FrsSearchContext->LdapMsg, &retcode,NULL,NULL,NULL,&CurrControls,FALSE);
  569. LDAP_FREE_MSG(FrsSearchContext->LdapMsg);
  570. FrsSearchContext->LdapMsg = NULL;
  571. if (LStatus == LDAP_SUCCESS) {
  572. LStatus = ldap_parse_page_control(ldap, CurrControls, &FrsSearchContext->TotalEntries, &CurrCookie);
  573. // under Exchange 5.5, before SP 2, this will fail with LDAP_CONTROL_NOT_FOUND when there are
  574. // no more search results. With Exchange 5.5 SP 2, this succeeds, and gives us a cookie that will
  575. // cause us to start over at the beginning of the search results.
  576. }
  577. if (LStatus == LDAP_SUCCESS) {
  578. if ( CurrCookie->bv_len == 0 && CurrCookie->bv_val == 0 ) {
  579. // under Exchange 5.5, SP 2, this means we're at the end of the results.
  580. // if we pass in this cookie again, we will start over at the beginning of the search results.
  581. LStatus = LDAP_CONTROL_NOT_FOUND;
  582. }
  583. ServerControls[0] = NULL;
  584. ServerControls[1] = NULL;
  585. if (LStatus == LDAP_SUCCESS) {
  586. LStatus = ldap_create_page_control(ldap,
  587. FrsSearchContext->PageSize,
  588. CurrCookie,
  589. FALSE,
  590. ServerControls);
  591. }
  592. ldap_controls_free(CurrControls);
  593. CurrControls = NULL;
  594. ber_bvfree(CurrCookie);
  595. CurrCookie = NULL;
  596. }
  597. // continue the search with the new cookie
  598. if (LStatus == LDAP_SUCCESS) {
  599. LStatus = ldap_search_ext_s(ldap,
  600. FrsSearchContext->BaseDn,
  601. FrsSearchContext->Scope,
  602. FrsSearchContext->Filter,
  603. FrsSearchContext->Attrs,
  604. FALSE,
  605. ServerControls,
  606. NULL,
  607. NULL,
  608. 0,
  609. &FrsSearchContext->LdapMsg);
  610. if ( (LStatus != LDAP_SUCCESS) && (LStatus != LDAP_CONTROL_NOT_FOUND) )
  611. {
  612. // LDAP_CONTROL_NOT_FOUND means that we have reached the end of the search results
  613. // in Exchange 5.5, before SP 2 (the server doesn't return a page control when there
  614. // are no more pages, so we get LDAP_CONTROL_NOT_FOUND when we try to extract the page
  615. // control from the search results).
  616. }
  617. }
  618. if (LStatus == LDAP_SUCCESS) {
  619. FrsSearchContext->EntriesInPage = ldap_count_entries(ldap, FrsSearchContext->LdapMsg);
  620. FrsSearchContext->CurrentEntry = 0;
  621. }
  622. return LdapMapErrorToWin32(LStatus);
  623. }
  624. PLDAPMessage
  625. LdapSearchNext(
  626. PLDAP ldap,
  627. PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
  628. )
  629. /*++
  630. Routine Description:
  631. Issue the ldap ldap_search_s call, check for errors, and check for
  632. a shutdown in progress.
  633. Arguments:
  634. ldap
  635. FrsSearchContext
  636. Return Value:
  637. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  638. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  639. --*/
  640. {
  641. DWORD WStatus = ERROR_SUCCESS;
  642. PLDAPMessage NextEntry = NULL;
  643. if (FrsSearchContext->bOpen != TRUE) {
  644. NextEntry = NULL;
  645. } else {
  646. if (FrsSearchContext->EntriesInPage > FrsSearchContext->CurrentEntry ) {
  647. // return the next entry from the current page
  648. return LdapSearchGetNextEntry(ldap, FrsSearchContext);
  649. } else {
  650. // see if there are more pages of results to get
  651. WStatus = LdapSearchGetNextPage(ldap, FrsSearchContext);
  652. if (WStatus == ERROR_SUCCESS) {
  653. return LdapSearchGetNextEntry(ldap, FrsSearchContext);
  654. }
  655. }
  656. }
  657. return NextEntry;
  658. }
  659. VOID
  660. LdapSearchClose(
  661. PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
  662. )
  663. /*++
  664. Routine Description:
  665. Issue the ldap ldap_search_s call, check for errors, and check for
  666. a shutdown in progress.
  667. Arguments:
  668. ldap
  669. FrsSearchContext
  670. Return Value:
  671. The ldap array of values or NULL if the Base, DesiredAttr, or its values
  672. does not exist. The ldap array is freed with LDAP_FREE_VALUES().
  673. --*/
  674. {
  675. FrsSearchContext->bOpen = FALSE;
  676. FrsSearchContext->EntriesInPage = 0;
  677. FrsSearchContext->CurrentEntry = 0;
  678. FrsSearchContext->TotalEntries = 0;
  679. FREE(FrsSearchContext->Filter);
  680. FREE(FrsSearchContext->BaseDn);
  681. if (FrsSearchContext->LdapMsg != NULL) {
  682. LDAP_FREE_MSG(FrsSearchContext->LdapMsg);
  683. }
  684. }
  685. PWCHAR
  686. GetRootDn(
  687. PLDAP Ldap,
  688. PWCHAR NamingContext
  689. )
  690. /*++
  691. Routine Description:
  692. Arguments:
  693. Return Value:
  694. --*/
  695. {
  696. PWCHAR Root; // DS pathname of configuration container
  697. PWCHAR *Values; // values from the attribute "namingContexts"
  698. DWORD NumVals; // number of values
  699. //
  700. // Return all of the values for the attribute namingContexts
  701. //
  702. Values = GetValues(Ldap, ATTR_ROOT, ATTR_NAMING_CONTEXTS, FALSE);
  703. if (Values == NULL) {
  704. return NULL;
  705. }
  706. //
  707. // Find the naming context that begins with CN=Configuration
  708. //
  709. NumVals = ldap_count_values(Values);
  710. while (NumVals--) {
  711. Root = wcsstr(Values[NumVals], NamingContext);
  712. if (Root != NULL && Root == Values[NumVals]) {
  713. Root = FrsWcsDup(Root);
  714. LDAP_FREE_VALUES(Values);
  715. return Root;
  716. }
  717. }
  718. DPRINT1("ERROR - COULD NOT FIND %ws\n", NamingContext);
  719. LDAP_FREE_VALUES(Values);
  720. return NULL;
  721. }
  722. PWCHAR
  723. ExtendDn(
  724. PWCHAR Dn,
  725. PWCHAR Cn
  726. )
  727. /*++
  728. Routine Description:
  729. Extend an existing DN with a new CN= component.
  730. Arguments:
  731. Dn - distinguished name
  732. Cn - common name
  733. Return Value:
  734. CN=Cn,Dn
  735. --*/
  736. {
  737. ULONG Len;
  738. PWCHAR NewDn;
  739. Len = wcslen(L"CN=,") + wcslen(Dn) + wcslen(Cn) + 1;
  740. NewDn = (PWCHAR)malloc(Len * sizeof(WCHAR));
  741. wcscpy(NewDn, L"CN=");
  742. wcscat(NewDn, Cn);
  743. wcscat(NewDn, L",");
  744. wcscat(NewDn, Dn);
  745. return NewDn;
  746. }
  747. PVOID *
  748. FindValues(
  749. PLDAPMessage LdapEntry,
  750. PWCHAR DesiredAttr,
  751. BOOL DoBerValues
  752. )
  753. /*++
  754. Routine Description:
  755. Return the DS values for one attribute in an entry.
  756. Arguments:
  757. Ldap - An open, bound ldap port.
  758. LdapEntry - An ldap entry returned by ldap_search_s()
  759. DesiredAttr - Return values for this attribute.
  760. DoVerValues - Return the bervals
  761. Return Value:
  762. An array of char pointers that represents the values for the attribute.
  763. The caller must free the array with LDAP_FREE_VALUES(). NULL if unsuccessful.
  764. --*/
  765. {
  766. PWCHAR LdapAttr; // Retrieved from an ldap entry
  767. BerElement *Ber; // Needed for scanning attributes
  768. //
  769. // Search the entry for the desired attribute
  770. //
  771. for (LdapAttr = ldap_first_attribute(pLdap, LdapEntry, &Ber);
  772. LdapAttr != NULL;
  773. LdapAttr = ldap_next_attribute(pLdap, LdapEntry, Ber)) {
  774. if (_wcsicmp(DesiredAttr, LdapAttr) == 0) {
  775. //
  776. // Return the values for DesiredAttr
  777. //
  778. if (DoBerValues) {
  779. return (PVOID *)ldap_get_values_len(pLdap, LdapEntry, LdapAttr);
  780. } else {
  781. return (PVOID *)ldap_get_values(pLdap, LdapEntry, LdapAttr);
  782. }
  783. }
  784. }
  785. return NULL;
  786. }
  787. PWCHAR
  788. FindValue(
  789. PLDAPMessage LdapEntry,
  790. PWCHAR DesiredAttr
  791. )
  792. /*++
  793. Routine Description:
  794. Return a copy of the first DS value for one attribute in an entry.
  795. Arguments:
  796. Ldap - An open, bound ldap port.
  797. LdapEntry - An ldap entry returned by ldap_search_s()
  798. DesiredAttr - Return values for this attribute.
  799. Return Value:
  800. A zero-terminated string or NULL if the attribute or its value
  801. doesn't exist. The string is freed with FREE().
  802. --*/
  803. {
  804. PWCHAR Val;
  805. PWCHAR *Values;
  806. // Get ldap's array of values
  807. Values = (PWCHAR *)FindValues(LdapEntry, DesiredAttr, FALSE);
  808. // Copy the first value (if any)
  809. if (Values) {
  810. Val = new WCHAR[wcslen(Values[0]) + 1];
  811. wcscpy(Val, Values[0]);
  812. } else {
  813. Val = NULL;
  814. }
  815. // Free ldap's array of values
  816. LDAP_FREE_VALUES(Values);
  817. return Val;
  818. }
  819. BOOL
  820. FindBerValue(
  821. PLDAPMessage Entry,
  822. PWCHAR DesiredAttr,
  823. ULONG *Len,
  824. VOID **Value
  825. )
  826. /*++
  827. Routine Description:
  828. Return a copy of the attributes object's schedule
  829. Arguments:
  830. ldap - An open, bound ldap port.
  831. Entry - An ldap entry returned by ldap_search_s()
  832. DesiredAttr - desired attribute
  833. Len - length of Value
  834. Value - binary value
  835. Return Value:
  836. The address of a schedule or NULL. Free with FrsFree().
  837. --*/
  838. {
  839. PLDAP_BERVAL *Values;
  840. *Len = 0;
  841. *Value = NULL;
  842. //
  843. // Get ldap's array of values
  844. //
  845. Values = (PLDAP_BERVAL *)FindValues(Entry, DesiredAttr, TRUE);
  846. if (!Values) {
  847. return FALSE;
  848. }
  849. //
  850. // Return a copy of the schedule
  851. //
  852. *Len = Values[0]->bv_len;
  853. if (*Len) {
  854. *Value = new WCHAR[*Len];
  855. CopyMemory(*Value, Values[0]->bv_val, *Len);
  856. }
  857. LDAP_FREE_BER_VALUES(Values);
  858. return TRUE;
  859. }
  860. PBYTE
  861. ReadScheduleFile(
  862. PWCHAR FileName
  863. )
  864. /*++
  865. Routine Description:
  866. Read a Hex formated byte array for a 7x24 schedule from a file.
  867. Convert to a 7x24 binary schedule.
  868. Arguments:
  869. FileName - Name of schedule file.
  870. Return Value:
  871. ptr to schedule data array or NULL if invalid param.
  872. --*/
  873. {
  874. HANDLE FileHandle;
  875. PBYTE SchedData;
  876. DWORD WStatus;
  877. DWORD BytesRead;
  878. DWORD DataByte, i, Day, Hour;
  879. ULONG Remaining;
  880. PCHAR pTC;
  881. CHAR SchedText[FRST_SIZE_OF_SCHEDULE_GRID*3 + 50];
  882. SchedData = new BYTE[FRST_SIZE_OF_SCHEDULE_GRID];
  883. if (SchedData == NULL) {
  884. printf("Error allocating memory.\n");
  885. return NULL;
  886. }
  887. FileHandle = CreateFileW(
  888. FileName, // lpszName
  889. GENERIC_READ | GENERIC_WRITE, // fdwAccess
  890. FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
  891. NULL, // lpsa
  892. OPEN_EXISTING, // fdwCreate
  893. FILE_ATTRIBUTE_NORMAL, // fdwAttrAndFlags
  894. NULL); // hTemplateFile
  895. if (!HANDLE_IS_VALID(FileHandle)) {
  896. WStatus = GetLastError();
  897. printf("Error opening %ws WStatus: %d\n", FileName, WStatus);
  898. FREE(SchedData);
  899. return NULL;
  900. }
  901. if (!ReadFile(FileHandle, SchedText, sizeof(SchedText), &BytesRead, NULL)) {
  902. WStatus = GetLastError();
  903. printf("Error reading %ws WStatus: %d\n", FileName, WStatus);
  904. FREE(SchedData);
  905. FRS_CLOSE(FileHandle);
  906. return NULL;
  907. }
  908. //
  909. // remove any white-space chars, including CR-LF, used for formatting.
  910. //
  911. Remaining = BytesRead;
  912. pTC = SchedText;
  913. while (Remaining > 0) {
  914. if (isspace((LONG) *pTC)) {
  915. memcpy(pTC, pTC+1, Remaining-1);
  916. } else {
  917. pTC++;
  918. }
  919. Remaining -= 1;
  920. }
  921. BytesRead = pTC - SchedText;
  922. if (BytesRead < FRST_SIZE_OF_SCHEDULE_GRID*2) {
  923. printf("Error reading %ws Expecting %d bytes, Actual was %d bytes. Could be too much whitespace.\n",
  924. FileName, FRST_SIZE_OF_SCHEDULE_GRID*2, BytesRead);
  925. FREE(SchedData);
  926. FRS_CLOSE(FileHandle);
  927. return NULL;
  928. }
  929. //
  930. // Result should be exactly the right size.
  931. //
  932. if (BytesRead != FRST_SIZE_OF_SCHEDULE_GRID*2) {
  933. printf("Error reading %ws Expecting %d bytes, Actual was %d bytes\n",
  934. FileName, FRST_SIZE_OF_SCHEDULE_GRID*2, BytesRead);
  935. FREE(SchedData);
  936. FRS_CLOSE(FileHandle);
  937. return NULL;
  938. }
  939. //
  940. // Convert to binary.
  941. //
  942. for (i=0; i<FRST_SIZE_OF_SCHEDULE_GRID; i++) {
  943. if (sscanf(&SchedText[i*2], "%2x", &DataByte) != 1) {
  944. SchedText[i*2+2] = '\0';
  945. printf("Error reading %ws Invalid hex data (%s) for schedule byte %d.\n",
  946. FileName, &SchedText[i*2], i);
  947. FREE(SchedData);
  948. FRS_CLOSE(FileHandle);
  949. return NULL;
  950. }
  951. SchedData[i] = (BYTE) DataByte;
  952. }
  953. FRS_CLOSE(FileHandle);
  954. return SchedData;
  955. }
  956. DWORD
  957. BuildSchedule(
  958. PBYTE *ppSchedule,
  959. DWORD Interval,
  960. DWORD Stagger,
  961. DWORD Offset
  962. )
  963. /*++
  964. Routine Description:
  965. Build the schedule structure.
  966. Arguments:
  967. ppSchedule - pointer to return the schedule in.
  968. Return Value:
  969. winerror.
  970. --*/
  971. {
  972. BYTE ScheduleData[FRST_SIZE_OF_SCHEDULE_GRID];
  973. UINT i, Day, Hour;
  974. DWORD Status = ERROR_SUCCESS;
  975. *ppSchedule = new BYTE[FRST_SIZE_OF_SCHEDULE];
  976. if (*ppSchedule == NULL) {
  977. return ERROR_NOT_ENOUGH_MEMORY;
  978. }
  979. //
  980. // Set the values for the elements of the SCHEDULE structure.
  981. //
  982. ((PSCHEDULE)*ppSchedule)->Size = FRST_SIZE_OF_SCHEDULE;
  983. ((PSCHEDULE)*ppSchedule)->Bandwidth = 0;
  984. ((PSCHEDULE)*ppSchedule)->NumberOfSchedules = 1;
  985. ((PSCHEDULE)*ppSchedule)->Schedules->Type = SCHEDULE_INTERVAL;
  986. ((PSCHEDULE)*ppSchedule)->Schedules->Offset = sizeof(SCHEDULE);
  987. //
  988. // Building the ScheduleData array depending on the requested schedule.
  989. //
  990. for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
  991. if (Interval == 0) {
  992. ScheduleData[i] = 0x00;
  993. } else if (i < (Offset*Interval)) {
  994. ScheduleData[i] = 0x00;
  995. } else if ((i-(Offset*Interval))%(Interval * Stagger) == 0) {
  996. ScheduleData[i] = 0x01;
  997. } else {
  998. ScheduleData[i] = 0x00;
  999. }
  1000. }
  1001. //
  1002. // Use the supplied schedule mask to turn off regions of the above schedule.
  1003. //
  1004. if (SchedMask != NULL) {
  1005. for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
  1006. ScheduleData[i] &= ~SchedMask[i];
  1007. }
  1008. }
  1009. //
  1010. // Apply the supplied override schedule to regions of the above schedule.
  1011. //
  1012. if (SchedOverride != NULL) {
  1013. for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
  1014. ScheduleData[i] |= SchedOverride[i];
  1015. }
  1016. }
  1017. memcpy((*ppSchedule)+sizeof(SCHEDULE),ScheduleData, FRST_SIZE_OF_SCHEDULE_GRID);
  1018. return Status;
  1019. }
  1020. #if 0
  1021. DWORD
  1022. DeleteSubscription(
  1023. PWCHAR NTFRSSettingsDn,
  1024. PWCHAR ReplicaSetName,
  1025. PWCHAR MemberName,
  1026. PWCHAR ComputerDn
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Delete a Subscription.
  1031. Arguments:
  1032. Return Value:
  1033. --*/
  1034. {
  1035. LDAPMod **Mod = NULL;
  1036. DWORD LStatus = LDAP_SUCCESS;
  1037. DWORD Status = MKDSOE_SUCCESS;
  1038. PWCHAR ReplicaSetDn = NULL;
  1039. PWCHAR MemberDn = NULL;
  1040. PWCHAR SubscriptionDn = NULL;
  1041. PWCHAR MemberAttrs[3];
  1042. PWCHAR SubscriptionAttrs[3];
  1043. PWCHAR SearchFilter = NULL;
  1044. DWORD NoOfMembers;
  1045. DWORD NoOfSubscriptions;
  1046. PWCHAR LocalComputerDn = NULL;
  1047. PLDAPMessage LdapEntry = NULL;
  1048. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1049. MK_ATTRS_2(MemberAttrs, ATTR_DN, ATTR_COMPUTER_REF);
  1050. MK_ATTRS_2(SubscriptionAttrs, ATTR_DN, ************ ATTR_MEMBER_REF);
  1051. //
  1052. // We need to get to the member object and the computer object.
  1053. // To get to the member object we need the member name or the computer dn.
  1054. // To get to the computer object we need a member with valid computerref
  1055. // or the computerdn parameter.
  1056. //
  1057. if ((MemberName == NULL) && (ComputerDn == NULL)) {
  1058. printf("ERROR: MemberName and ComputerDn are NULL in DeleteSubscription.\n");
  1059. Status = MKDSOE_BAD_ARG;
  1060. return Status;
  1061. }
  1062. SearchFilter = (PWCHAR) malloc((max((ComputerDn != NULL)?wcslen(ComputerDn):0,
  1063. (MemberDn != NULL)?wcslen(MemberDn):0)
  1064. + MAX_PATH)
  1065. * sizeof(WCHAR));
  1066. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  1067. if (MemberName != NULL) {
  1068. MemberDn = ExtendDn(ReplicaSetDn, MemberName);
  1069. } else {
  1070. //
  1071. // Use computerdn to get the memberdn.
  1072. //
  1073. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  1074. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  1075. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1076. Status = MKDSOE_SUBSCRIPTION_DELETE_FAILED;
  1077. goto CLEANUP;
  1078. }
  1079. NoOfMembers = FrsSearchContext.EntriesInPage;
  1080. if (NoOfMembers == 0) {
  1081. printf("Error deleting Subscription; member not found.\n");
  1082. LdapSearchClose(&FrsSearchContext);
  1083. Status = MKDSOE_SUBSCRIPTION_NOT_FOUND_DELETE;
  1084. goto CLEANUP;
  1085. }
  1086. if (NoOfMembers > 1) {
  1087. printf("Error deleting Subscription; duplicate members found.\n");
  1088. LdapSearchClose(&FrsSearchContext);
  1089. Status = MKDSOE_SUBSCRIPTION_DUPS_FOUND_DELETE;
  1090. goto CLEANUP;
  1091. }
  1092. //
  1093. // Scan the entries returned from ldap_search
  1094. //
  1095. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1096. LdapEntry != NULL;
  1097. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1098. MemberDn = FindValue(LdapEntry, ATTR_DN);
  1099. }
  1100. LdapSearchClose(&FrsSearchContext);
  1101. }
  1102. DPRINT1("MemberDn:%ws\n", MemberDn);
  1103. if (ComputerDn == NULL) {
  1104. //
  1105. // Use MemberDn to find the computerDn. We will come here
  1106. // only if MemberName is supplied but computerdn is not.
  1107. //
  1108. if (!LdapSearchInit(pLdap, MemberDn, LDAP_SCOPE_BASE, NULL,
  1109. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1110. Status = MKDSOE_SUBSCRIPTION_DELETE_FAILED;
  1111. goto CLEANUP;
  1112. }
  1113. NoOfMembers = FrsSearchContext.EntriesInPage;
  1114. if (NoOfMembers == 0) {
  1115. printf("Error deleting Subscription; member not found.\n");
  1116. LdapSearchClose(&FrsSearchContext);
  1117. Status = MKDSOE_SUBSCRIPTION_NOT_FOUND_DELETE;
  1118. goto CLEANUP;
  1119. }
  1120. //
  1121. // Scan the entries returned from ldap_search
  1122. //
  1123. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1124. LdapEntry != NULL;
  1125. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1126. LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  1127. if (LocalComputerDn == NULL) {
  1128. printf("Error deleting Subscription; computerdn not found.\n");
  1129. LdapSearchClose(&FrsSearchContext);
  1130. Status = MKDSOE_SUBSCRIPTION_NOT_FOUND_DELETE;
  1131. goto CLEANUP;
  1132. }
  1133. }
  1134. LdapSearchClose(&FrsSearchContext);
  1135. } else {
  1136. LocalComputerDn = FrsWcsDup(ComputerDn);
  1137. }
  1138. //
  1139. // We have the computerdn and the memberdn. Now check if a Subscription
  1140. // already exists.
  1141. //
  1142. WCS_CAT7(SearchFilter, L"(&(", ATTR_MEMBER_REF, L"=", MemberDn, L")" , CLASS_SUBSCRIPTION, L")");
  1143. if (!LdapSearchInit(pLdap, LocalComputerDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  1144. SubscriptionAttrs, 0, &FrsSearchContext, FALSE)) {
  1145. Status = MKDSOE_SUBSCRIPTION_DELETE_FAILED;
  1146. goto CLEANUP;
  1147. }
  1148. NoOfSubscriptions = FrsSearchContext.EntriesInPage;
  1149. if ((NoOfSubscriptions > 1) && (bAffectAll != TRUE)) {
  1150. printf("Duplicate Subscriptions found. Deleting all.\n");
  1151. LdapSearchClose(&FrsSearchContext);
  1152. Status = MKDSOE_SUBSCRIPTION_DUPS_FOUND_DELETE;
  1153. goto CLEANUP;
  1154. }
  1155. if (NoOfSubscriptions != 0) {
  1156. //
  1157. // Scan the entries returned from ldap_search
  1158. //
  1159. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1160. LdapEntry != NULL;
  1161. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1162. SubscriptionDn = FindValue(LdapEntry, ATTR_DN);
  1163. DPRINT1("Deleting Dn:%ws\n", SubscriptionDn);
  1164. if (bDebugMode) {
  1165. DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", SubscriptionDn);
  1166. } else {
  1167. LStatus = ldap_delete_s(pLdap, SubscriptionDn);
  1168. if (LStatus != LDAP_SUCCESS) {
  1169. printf("ERROR - Can't delete %ws: %ws\n",
  1170. SubscriptionDn, ldap_err2string(LStatus));
  1171. Status = MKDSOE_SUBSCRIPTION_DELETE_FAILED;
  1172. }
  1173. }
  1174. FREE(SubscriptionDn);
  1175. }
  1176. } else {
  1177. printf("Warning deleting; Subscription not found.\n");
  1178. Status = MKDSOE_SUBSCRIPTION_NOT_FOUND_DELETE;
  1179. }
  1180. LdapSearchClose(&FrsSearchContext);
  1181. CLEANUP:
  1182. FREE(SearchFilter);
  1183. FREE(ReplicaSetDn);
  1184. FREE(MemberDn);
  1185. FREE(LocalComputerDn);
  1186. FREE(SubscriptionDn);
  1187. FreeMod(&Mod);
  1188. return Status;
  1189. }
  1190. DWORD
  1191. UpdateSubscription(
  1192. PWCHAR SubscriptionDn,
  1193. PWCHAR MemberRef,
  1194. PWCHAR RootPath,
  1195. PWCHAR StagePath
  1196. )
  1197. /*++
  1198. Routine Description:
  1199. Update the Subscription.
  1200. Arguments:
  1201. Return Value:
  1202. --*/
  1203. {
  1204. LDAPMod **Mod = NULL;
  1205. DWORD LStatus = LDAP_SUCCESS;
  1206. DWORD Status = MKDSOE_SUCCESS;
  1207. PWCHAR Attrs[5];
  1208. PLDAPMessage LdapEntry = NULL;
  1209. PWCHAR CurMemberRef = NULL;
  1210. PWCHAR CurRootPath = NULL;
  1211. PWCHAR CurStagePath = NULL;
  1212. DWORD NoOfSubscriptions;
  1213. BOOL bNeedsUpdate = FALSE;
  1214. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1215. MK_ATTRS_4(Attrs, ATTR_DN, ATTR_MEMBER_REF, ATTR_REPLICA_ROOT, ATTR_REPLICA_STAGE);
  1216. if (!LdapSearchInit(pLdap, SubscriptionDn, LDAP_SCOPE_BASE, NULL,
  1217. Attrs, 0, &FrsSearchContext, FALSE)) {
  1218. Status = MKDSOE_SUBSCRIPTION_OBJ_UPDATE_FAILED;
  1219. goto CLEANUP;
  1220. }
  1221. NoOfSubscriptions = FrsSearchContext.EntriesInPage;
  1222. if (NoOfSubscriptions == 0) {
  1223. printf("Error updating; Subscription not found.\n");
  1224. LdapSearchClose(&FrsSearchContext);
  1225. Status = MKDSOE_SUBSCRIPTION_NOT_FOUND_UPDATE;
  1226. goto CLEANUP;
  1227. }
  1228. //
  1229. // Scan the entries returned from ldap_search
  1230. //
  1231. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1232. LdapEntry != NULL;
  1233. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1234. CurMemberRef = FindValue(LdapEntry, ATTR_MEMBER_REF);
  1235. CurRootPath = FindValue(LdapEntry, ATTR_REPLICA_ROOT);
  1236. CurStagePath = FindValue(LdapEntry, ATTR_REPLICA_STAGE);
  1237. }
  1238. LdapSearchClose(&FrsSearchContext);
  1239. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  1240. // Check ATTR_MEMBER_REF
  1241. // if a ref is supplied then make sure it is same as the current ref.
  1242. // if a ref is not supplied then leave it as it is.
  1243. if (MemberRef != NULL) {
  1244. if ((CurMemberRef == NULL) ||
  1245. ((CurMemberRef != NULL) && wcscmp(MemberRef, CurMemberRef))) {
  1246. AddMod(ATTR_MEMBER_REF, MemberRef, &Mod);
  1247. bNeedsUpdate = TRUE;
  1248. DPRINT1(" New FrsMemberReference:%ws\n", MemberRef);
  1249. }
  1250. }
  1251. // Check ATTR_REPLICA_ROOT
  1252. // if a path is supplied then make sure it is same as the current path.
  1253. // if a path is not supplied then leave it as it is.
  1254. if (RootPath != NULL) {
  1255. if ((CurRootPath == NULL) ||
  1256. ((CurRootPath != NULL) && wcscmp(RootPath, CurRootPath))) {
  1257. AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
  1258. bNeedsUpdate = TRUE;
  1259. DPRINT1(" New FrsRootPath:%ws\n", RootPath);
  1260. }
  1261. }
  1262. // Check ATTR_REPLICA_STAGE
  1263. // if a path is supplied then make sure it is same as the current path.
  1264. // if a path is not supplied then leave it as it is.
  1265. if (StagePath != NULL) {
  1266. if ((CurStagePath == NULL) ||
  1267. ((CurStagePath != NULL) && wcscmp(StagePath, CurStagePath))) {
  1268. AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
  1269. bNeedsUpdate = TRUE;
  1270. DPRINT1(" New FrsRootPath:%ws\n", StagePath);
  1271. }
  1272. }
  1273. if (bNeedsUpdate) {
  1274. if (bDebugMode) {
  1275. DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  1276. } else {
  1277. LStatus = ldap_modify_s(pLdap, SubscriptionDn, Mod);
  1278. if (LStatus != LDAP_SUCCESS) {
  1279. printf("ERROR - Can't update %ws: %ws\n",
  1280. SubscriptionDn, ldap_err2string(LStatus));
  1281. Status = MKDSOE_SUBSCRIPTION_OBJ_UPDATE_FAILED;
  1282. }
  1283. }
  1284. } else {
  1285. printf("No update required\n");
  1286. }
  1287. CLEANUP:
  1288. FREE(CurMemberRef);
  1289. FREE(CurRootPath);
  1290. FREE(CurStagePath);
  1291. FreeMod(&Mod);
  1292. return Status;
  1293. }
  1294. DWORD
  1295. CreateNewSubscription(
  1296. PWCHAR NTFRSSettingsDn,
  1297. PWCHAR ReplicaSetName,
  1298. PWCHAR MemberName,
  1299. PWCHAR ComputerDn,
  1300. PWCHAR RootPath,
  1301. PWCHAR StagePath,
  1302. PWCHAR RefDCName
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. Create a new Subscription.
  1307. Arguments:
  1308. Return Value:
  1309. --*/
  1310. {
  1311. LDAPMod **Mod = NULL;
  1312. DWORD LStatus = LDAP_SUCCESS;
  1313. DWORD Status = MKDSOE_SUCCESS;
  1314. PWCHAR ReplicaSetDn = NULL;
  1315. PWCHAR MemberDn = NULL;
  1316. PWCHAR SubscriptionDn = NULL;
  1317. PWCHAR MemberAttrs[3];
  1318. PWCHAR SubscriptionAttrs[3];
  1319. PWCHAR SearchFilter = NULL;
  1320. DWORD NoOfMembers;
  1321. DWORD NoOfSubscriptions;
  1322. PWCHAR LocalComputerDn = NULL;
  1323. PLDAPMessage LdapEntry = NULL;
  1324. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1325. MK_ATTRS_2(MemberAttrs, ATTR_DN, ATTR_COMPUTER_REF);
  1326. MK_ATTRS_2(SubscriptionAttrs, ************* ATTR_DN, ATTR_MEMBER_REF);
  1327. //
  1328. // We need to get to the member object and the computer object.
  1329. // To get to the member object we need the member name or the computer dn.
  1330. //
  1331. // To get to the computer object we need a member with valid computerref
  1332. // or the computerdn parameter.
  1333. //
  1334. if ((MemberName == NULL) && (ComputerDn == NULL)) {
  1335. Status = MKDSOE_BAD_ARG;
  1336. return Status;
  1337. }
  1338. SearchFilter = (PWCHAR) malloc((max((ComputerDn != NULL)?wcslen(ComputerDn):0,
  1339. (MemberDn != NULL)?wcslen(MemberDn):0)
  1340. + MAX_PATH)
  1341. * sizeof(WCHAR));
  1342. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  1343. if (MemberName != NULL) {
  1344. MemberDn = ExtendDn(ReplicaSetDn, MemberName);
  1345. } else {
  1346. //
  1347. // Use computerdn to get the memberdn.
  1348. //
  1349. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  1350. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  1351. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1352. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1353. goto CLEANUP;
  1354. }
  1355. NoOfMembers = FrsSearchContext.EntriesInPage;
  1356. if (NoOfMembers == 0) {
  1357. printf("Error creating Subscription; member not found.\n");
  1358. LdapSearchClose(&FrsSearchContext);
  1359. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1360. goto CLEANUP;
  1361. }
  1362. if (NoOfMembers > 1) {
  1363. printf("Error creating Subscription; duplicate members found.\n");
  1364. LdapSearchClose(&FrsSearchContext);
  1365. Status = MKDSOE_SUBSCRIPTION_DUPS_FOUND_UPDATE;
  1366. goto CLEANUP;
  1367. }
  1368. //
  1369. // Scan the entries returned from ldap_search
  1370. //
  1371. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1372. LdapEntry != NULL;
  1373. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1374. MemberDn = FindValue(LdapEntry, ATTR_DN);
  1375. }
  1376. LdapSearchClose(&FrsSearchContext);
  1377. }
  1378. DPRINT1("MemberDn:%ws\n", MemberDn);
  1379. if (ComputerDn == NULL) {
  1380. //
  1381. // Use MemberDn to find the computerDn. We will come here
  1382. // only if MemberName is supplied but computerdn is not.
  1383. //
  1384. if (!LdapSearchInit(pLdap, MemberDn, LDAP_SCOPE_BASE, NULL,
  1385. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1386. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1387. goto CLEANUP;
  1388. }
  1389. NoOfMembers = FrsSearchContext.EntriesInPage;
  1390. if (NoOfMembers == 0) {
  1391. printf("Error creating Subscription; member not found.\n");
  1392. LdapSearchClose(&FrsSearchContext);
  1393. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1394. goto CLEANUP;
  1395. }
  1396. //
  1397. // Scan the entries returned from ldap_search
  1398. //
  1399. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1400. LdapEntry != NULL;
  1401. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1402. LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  1403. if (LocalComputerDn == NULL) {
  1404. printf("Error creating Subscription; computerdn not found.\n");
  1405. LdapSearchClose(&FrsSearchContext);
  1406. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1407. goto CLEANUP;
  1408. }
  1409. }
  1410. LdapSearchClose(&FrsSearchContext);
  1411. } else {
  1412. LocalComputerDn = FrsWcsDup(ComputerDn);
  1413. }
  1414. //
  1415. // We have the computerdn and the memberdn. Now check if a Subscription
  1416. // already exists.
  1417. //
  1418. WCS_CAT7(SearchFilter, L"(&(", ATTR_MEMBER_REF, L"=", MemberDn, L")" , CLASS_SUBSCRIPTION, L")");
  1419. if (!LdapSearchInit(pLdap, LocalComputerDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  1420. SubscriptionAttrs, 0, &FrsSearchContext, FALSE)) {
  1421. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1422. goto CLEANUP;
  1423. }
  1424. NoOfSubscriptions = FrsSearchContext.EntriesInPage;
  1425. if (NoOfSubscriptions > 1) {
  1426. printf("Error creating Subscription; duplicate found.\n");
  1427. LdapSearchClose(&FrsSearchContext);
  1428. Status = MKDSOE_SUBSCRIPTION_DUPS_FOUND_UPDATE;
  1429. goto CLEANUP;
  1430. }
  1431. if (NoOfSubscriptions == 1) {
  1432. //
  1433. // Scan the entries returned from ldap_search
  1434. //
  1435. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1436. LdapEntry != NULL;
  1437. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1438. SubscriptionDn = FindValue(LdapEntry, ATTR_DN);
  1439. }
  1440. Status = UpdateSubscription(SubscriptionDn, MemberDn, RootPath, StagePath);
  1441. } else {
  1442. SubscriptionDn = ExtendDn(LocalComputerDn, MKDSOE_SUBSCRIPTION);
  1443. // ATTR_DN
  1444. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  1445. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  1446. if (bDebugMode) {
  1447. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  1448. } else {
  1449. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  1450. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  1451. printf("ERROR - Can't create %ws: %ws\n",
  1452. SubscriptionDn, ldap_err2string(LStatus));
  1453. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1454. goto CLEANUP;
  1455. }
  1456. }
  1457. FreeMod(&Mod);
  1458. ************ check
  1459. SubscriptionDn = ExtendDn(SubscriptionDn, ReplicaSetName);
  1460. // ATTR_DN
  1461. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  1462. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTION, &Mod);
  1463. // ATTR_MEMBER_REF
  1464. AddMod(ATTR_MEMBER_REF, MemberDn, &Mod);
  1465. DPRINT1(" FrsMemberReference:%ws\n", MemberDn);
  1466. // ATTR_REPLICA_ROOT
  1467. AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
  1468. DPRINT1(" FrsRootPath:%ws\n", RootPath);
  1469. // ATTR_REPLICA_STAGE
  1470. AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
  1471. DPRINT1(" FrsStagePath:%ws\n", StagePath);
  1472. if (bDebugMode) {
  1473. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  1474. } else {
  1475. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  1476. if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
  1477. //
  1478. // prepare the server hint. Needed in case the member object
  1479. // is just created on another DC than the one on which the
  1480. // Subscription is being created.
  1481. //
  1482. LDAPControl simpleControl;
  1483. PLDAPControl controlArray[2];
  1484. INT rc;
  1485. BERVAL* pBerVal = NULL;
  1486. BerElement* pBer;
  1487. pBer = ber_alloc_t(LBER_USE_DER);
  1488. if (!pBer)
  1489. {
  1490. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1491. goto CLEANUP;
  1492. }
  1493. DPRINT1("Sending binding DC Name %ws\n",RefDCName);
  1494. rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
  1495. if ( rc == -1 ) {
  1496. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1497. goto CLEANUP;
  1498. }
  1499. rc = ber_flatten(pBer, &pBerVal);
  1500. if (rc == -1)
  1501. {
  1502. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1503. goto CLEANUP;
  1504. }
  1505. ber_free(pBer,1);
  1506. controlArray[0] = &simpleControl;
  1507. controlArray[1] = NULL;
  1508. // simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
  1509. simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
  1510. simpleControl.ldctl_iscritical = TRUE;
  1511. simpleControl.ldctl_value = *pBerVal;
  1512. LStatus = ldap_add_ext_s(pLdap,
  1513. SubscriptionDn,
  1514. Mod,
  1515. (PLDAPControl *)&controlArray, //ServerControls,
  1516. NULL //ClientControls,
  1517. );
  1518. }
  1519. if (LStatus == LDAP_ALREADY_EXISTS) {
  1520. //
  1521. // If the object already exists then convert the create to an update.
  1522. // This is to allow the user to run the data file with creates twice without
  1523. // generating errors but only fixing the objects that have changed.
  1524. //
  1525. Status = UpdateSubscription(SubscriptionDn, MemberDn, RootPath, StagePath);
  1526. } else if (LStatus != LDAP_SUCCESS) {
  1527. DPRINT2("ERROR - Can't create %ws: %ws\n",
  1528. SubscriptionDn, ldap_err2string(LStatus));
  1529. Status = MKDSOE_SUBSCRIPTION_OBJ_CRE_FAILED;
  1530. }
  1531. }
  1532. }
  1533. LdapSearchClose(&FrsSearchContext);
  1534. CLEANUP:
  1535. FreeMod(&Mod);
  1536. FREE(ReplicaSetDn);
  1537. FREE(MemberDn);
  1538. FREE(SubscriptionDn);
  1539. FREE(SearchFilter);
  1540. FREE(LocalComputerDn);
  1541. return Status;
  1542. }
  1543. #endif 0
  1544. DWORD
  1545. DeleteSubscriber(
  1546. PWCHAR NTFRSSettingsDn,
  1547. PWCHAR ReplicaSetName,
  1548. PWCHAR MemberName,
  1549. PWCHAR ComputerDn
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. Delete a subscriber.
  1554. Arguments:
  1555. Return Value:
  1556. --*/
  1557. {
  1558. LDAPMod **Mod = NULL;
  1559. DWORD LStatus = LDAP_SUCCESS;
  1560. DWORD Status = MKDSOE_SUCCESS;
  1561. PWCHAR ReplicaSetDn = NULL;
  1562. PWCHAR MemberDn = NULL;
  1563. PWCHAR SubscriberDn = NULL;
  1564. PWCHAR MemberAttrs[3];
  1565. PWCHAR SubscriberAttrs[3];
  1566. PWCHAR SearchFilter = NULL;
  1567. DWORD NoOfMembers;
  1568. DWORD NoOfSubscribers;
  1569. PWCHAR LocalComputerDn = NULL;
  1570. PLDAPMessage LdapEntry = NULL;
  1571. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1572. MK_ATTRS_2(MemberAttrs, ATTR_DN, ATTR_COMPUTER_REF);
  1573. MK_ATTRS_2(SubscriberAttrs, ATTR_DN, ATTR_MEMBER_REF);
  1574. //
  1575. // We need to get to the member object and the computer object.
  1576. // To get to the member object we need the member name or the computer dn.
  1577. // To get to the computer object we need a member with valid computerref
  1578. // or the computerdn parameter.
  1579. //
  1580. if ((MemberName == NULL) && (ComputerDn == NULL)) {
  1581. printf("ERROR: MemberName and ComputerDn are NULL in DeleteSubscriber.\n");
  1582. Status = MKDSOE_BAD_ARG;
  1583. return Status;
  1584. }
  1585. SearchFilter = (PWCHAR) malloc((max((ComputerDn != NULL)?wcslen(ComputerDn):0,
  1586. (MemberDn != NULL)?wcslen(MemberDn):0)
  1587. + MAX_PATH)
  1588. * sizeof(WCHAR));
  1589. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  1590. if (MemberName != NULL) {
  1591. MemberDn = ExtendDn(ReplicaSetDn, MemberName);
  1592. } else {
  1593. //
  1594. // Use computerdn to get the memberdn.
  1595. //
  1596. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  1597. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  1598. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1599. Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
  1600. goto CLEANUP;
  1601. }
  1602. NoOfMembers = FrsSearchContext.EntriesInPage;
  1603. if (NoOfMembers == 0) {
  1604. printf("Error deleting subscriber; member not found.\n");
  1605. LdapSearchClose(&FrsSearchContext);
  1606. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
  1607. goto CLEANUP;
  1608. }
  1609. if (NoOfMembers > 1) {
  1610. printf("Error deleting subscriber; duplicate members found.\n");
  1611. LdapSearchClose(&FrsSearchContext);
  1612. Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE;
  1613. goto CLEANUP;
  1614. }
  1615. //
  1616. // Scan the entries returned from ldap_search
  1617. //
  1618. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1619. LdapEntry != NULL;
  1620. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1621. MemberDn = FindValue(LdapEntry, ATTR_DN);
  1622. }
  1623. LdapSearchClose(&FrsSearchContext);
  1624. }
  1625. DPRINT1("MemberDn:%ws\n", MemberDn);
  1626. if (ComputerDn == NULL) {
  1627. //
  1628. // Use MemberDn to find the computerDn. We will come here
  1629. // only if MemberName is supplied but computerdn is not.
  1630. //
  1631. if (!LdapSearchInit(pLdap, MemberDn, LDAP_SCOPE_BASE, NULL,
  1632. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1633. Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
  1634. goto CLEANUP;
  1635. }
  1636. NoOfMembers = FrsSearchContext.EntriesInPage;
  1637. if (NoOfMembers == 0) {
  1638. printf("Error deleting subscriber; member not found.\n");
  1639. LdapSearchClose(&FrsSearchContext);
  1640. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
  1641. goto CLEANUP;
  1642. }
  1643. //
  1644. // Scan the entries returned from ldap_search
  1645. //
  1646. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1647. LdapEntry != NULL;
  1648. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1649. LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  1650. if (LocalComputerDn == NULL) {
  1651. printf("Error deleting subscriber; computerdn not found.\n");
  1652. LdapSearchClose(&FrsSearchContext);
  1653. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
  1654. goto CLEANUP;
  1655. }
  1656. }
  1657. LdapSearchClose(&FrsSearchContext);
  1658. } else {
  1659. LocalComputerDn = FrsWcsDup(ComputerDn);
  1660. }
  1661. //
  1662. // We have the computerdn and the memberdn. Now check if a subscriber
  1663. // already exists.
  1664. //
  1665. WCS_CAT7(SearchFilter, L"(&(", ATTR_MEMBER_REF, L"=", MemberDn, L")" , CLASS_SUBSCRIBER, L")");
  1666. if (!LdapSearchInit(pLdap, LocalComputerDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  1667. SubscriberAttrs, 0, &FrsSearchContext, FALSE)) {
  1668. Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
  1669. goto CLEANUP;
  1670. }
  1671. NoOfSubscribers = FrsSearchContext.EntriesInPage;
  1672. if ((NoOfSubscribers > 1) && (bAffectAll != TRUE)) {
  1673. printf("Duplicate subscribers found. Deleting all.\n");
  1674. LdapSearchClose(&FrsSearchContext);
  1675. Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE;
  1676. goto CLEANUP;
  1677. }
  1678. if (NoOfSubscribers != 0) {
  1679. //
  1680. // Scan the entries returned from ldap_search
  1681. //
  1682. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1683. LdapEntry != NULL;
  1684. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1685. SubscriberDn = FindValue(LdapEntry, ATTR_DN);
  1686. DPRINT1("Deleting Dn:%ws\n", SubscriberDn);
  1687. if (bDebugMode) {
  1688. DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", SubscriberDn);
  1689. } else {
  1690. LStatus = ldap_delete_s(pLdap, SubscriberDn);
  1691. if (LStatus != LDAP_SUCCESS) {
  1692. printf("ERROR - Can't delete %ws: %ws\n",
  1693. SubscriberDn, ldap_err2string(LStatus));
  1694. Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
  1695. }
  1696. }
  1697. FREE(SubscriberDn);
  1698. }
  1699. } else {
  1700. printf("Warning deleting; subscriber not found.\n");
  1701. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
  1702. }
  1703. LdapSearchClose(&FrsSearchContext);
  1704. CLEANUP:
  1705. FREE(SearchFilter);
  1706. FREE(ReplicaSetDn);
  1707. FREE(MemberDn);
  1708. FREE(LocalComputerDn);
  1709. FREE(SubscriberDn);
  1710. FreeMod(&Mod);
  1711. return Status;
  1712. }
  1713. DWORD
  1714. UpdateSubscriber(
  1715. PWCHAR SubscriberDn,
  1716. PWCHAR MemberRef,
  1717. PWCHAR RootPath,
  1718. PWCHAR StagePath
  1719. )
  1720. /*++
  1721. Routine Description:
  1722. Update the subscriber.
  1723. Arguments:
  1724. Return Value:
  1725. --*/
  1726. {
  1727. LDAPMod **Mod = NULL;
  1728. DWORD LStatus = LDAP_SUCCESS;
  1729. DWORD Status = MKDSOE_SUCCESS;
  1730. PWCHAR Attrs[5];
  1731. PLDAPMessage LdapEntry = NULL;
  1732. PWCHAR CurMemberRef = NULL;
  1733. PWCHAR CurRootPath = NULL;
  1734. PWCHAR CurStagePath = NULL;
  1735. DWORD NoOfSubscribers;
  1736. BOOL bNeedsUpdate = FALSE;
  1737. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1738. MK_ATTRS_4(Attrs, ATTR_DN, ATTR_MEMBER_REF, ATTR_REPLICA_ROOT, ATTR_REPLICA_STAGE);
  1739. if (!LdapSearchInit(pLdap, SubscriberDn, LDAP_SCOPE_BASE, NULL,
  1740. Attrs, 0, &FrsSearchContext, FALSE)) {
  1741. Status = MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED;
  1742. goto CLEANUP;
  1743. }
  1744. NoOfSubscribers = FrsSearchContext.EntriesInPage;
  1745. if (NoOfSubscribers == 0) {
  1746. printf("Error updating; subscriber not found.\n");
  1747. LdapSearchClose(&FrsSearchContext);
  1748. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_UPDATE;
  1749. goto CLEANUP;
  1750. }
  1751. //
  1752. // Scan the entries returned from ldap_search
  1753. //
  1754. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1755. LdapEntry != NULL;
  1756. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1757. CurMemberRef = FindValue(LdapEntry, ATTR_MEMBER_REF);
  1758. CurRootPath = FindValue(LdapEntry, ATTR_REPLICA_ROOT);
  1759. CurStagePath = FindValue(LdapEntry, ATTR_REPLICA_STAGE);
  1760. }
  1761. LdapSearchClose(&FrsSearchContext);
  1762. DPRINT1("SubscriberDn:%ws\n", SubscriberDn);
  1763. // Check ATTR_MEMBER_REF
  1764. // if a ref is supplied then make sure it is same as the current ref.
  1765. // if a ref is not supplied then leave it as it is.
  1766. if (MemberRef != NULL) {
  1767. if ((CurMemberRef == NULL) ||
  1768. ((CurMemberRef != NULL) && wcscmp(MemberRef, CurMemberRef))) {
  1769. AddMod(ATTR_MEMBER_REF, MemberRef, &Mod);
  1770. bNeedsUpdate = TRUE;
  1771. DPRINT1(" New FrsMemberReference:%ws\n", MemberRef);
  1772. }
  1773. }
  1774. // Check ATTR_REPLICA_ROOT
  1775. // if a path is supplied then make sure it is same as the current path.
  1776. // if a path is not supplied then leave it as it is.
  1777. if (RootPath != NULL) {
  1778. if ((CurRootPath == NULL) ||
  1779. ((CurRootPath != NULL) && wcscmp(RootPath, CurRootPath))) {
  1780. AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
  1781. bNeedsUpdate = TRUE;
  1782. DPRINT1(" New FrsRootPath:%ws\n", RootPath);
  1783. }
  1784. }
  1785. // Check ATTR_REPLICA_STAGE
  1786. // if a path is supplied then make sure it is same as the current path.
  1787. // if a path is not supplied then leave it as it is.
  1788. if (StagePath != NULL) {
  1789. if ((CurStagePath == NULL) ||
  1790. ((CurStagePath != NULL) && wcscmp(StagePath, CurStagePath))) {
  1791. AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
  1792. bNeedsUpdate = TRUE;
  1793. DPRINT1(" New FrsStagePath:%ws\n", StagePath);
  1794. }
  1795. }
  1796. if (bNeedsUpdate) {
  1797. if (bDebugMode) {
  1798. DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", SubscriberDn);
  1799. } else {
  1800. LStatus = ldap_modify_s(pLdap, SubscriberDn, Mod);
  1801. if (LStatus != LDAP_SUCCESS) {
  1802. printf("ERROR - Can't update %ws: %ws\n",
  1803. SubscriberDn, ldap_err2string(LStatus));
  1804. Status = MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED;
  1805. }
  1806. }
  1807. } else {
  1808. printf("No update required\n");
  1809. }
  1810. CLEANUP:
  1811. FREE(CurMemberRef);
  1812. FREE(CurRootPath);
  1813. FREE(CurStagePath);
  1814. FreeMod(&Mod);
  1815. return Status;
  1816. }
  1817. DWORD
  1818. CreateNewSubscriber(
  1819. PWCHAR NTFRSSettingsDn,
  1820. PWCHAR ReplicaSetName,
  1821. PWCHAR MemberName,
  1822. PWCHAR ComputerDn,
  1823. PWCHAR RootPath,
  1824. PWCHAR StagePath,
  1825. PWCHAR WorkingPath,
  1826. PWCHAR RefDCName
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. Create a new subscriber.
  1831. Arguments:
  1832. Return Value:
  1833. --*/
  1834. {
  1835. LDAPMod **Mod = NULL;
  1836. DWORD LStatus = LDAP_SUCCESS;
  1837. DWORD Status = MKDSOE_SUCCESS;
  1838. PWCHAR ReplicaSetDn = NULL;
  1839. PWCHAR MemberDn = NULL;
  1840. PWCHAR SubscriberDn = NULL;
  1841. PWCHAR SubscriptionDn = NULL;
  1842. PWCHAR MemberAttrs[3];
  1843. PWCHAR SubscriberAttrs[3];
  1844. PWCHAR SearchFilter = NULL;
  1845. DWORD NoOfMembers;
  1846. DWORD NoOfSubscribers;
  1847. PWCHAR LocalComputerDn = NULL;
  1848. PLDAPMessage LdapEntry = NULL;
  1849. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  1850. PWCHAR SaveDn;
  1851. PWCHAR DFSRoot, DFSJunction;
  1852. DWORD Vbar;
  1853. if (bDFSNaming) {
  1854. Vbar = wcscspn(DFSName, L'|');
  1855. if ((Vbar == wcslen(DFSName) || (Vbar == 0)) {
  1856. //
  1857. // No vertical bar found.
  1858. //
  1859. Status = MKDSOE_BAD_ARG;
  1860. return Status;
  1861. }
  1862. //
  1863. // Extract the name components.
  1864. //
  1865. DFSRoot = FrsWcsDup(DFSName);
  1866. DFSRoot[Vbar] = L'\0';
  1867. DFSJunction = &DFSName[Vbar+1];
  1868. }
  1869. MK_ATTRS_2(MemberAttrs, ATTR_DN, ATTR_COMPUTER_REF);
  1870. MK_ATTRS_2(SubscriberAttrs, ATTR_DN, ATTR_MEMBER_REF);
  1871. //
  1872. // We need to get to the member object and the computer object.
  1873. // To get to the member object we need the member name or the computer dn.
  1874. //
  1875. // To get to the computer object we need a member with valid computerref
  1876. // or the computerdn parameter.
  1877. //
  1878. if ((MemberName == NULL) && (ComputerDn == NULL)) {
  1879. Status = MKDSOE_BAD_ARG;
  1880. return Status;
  1881. }
  1882. SearchFilter = (PWCHAR) malloc((max((ComputerDn != NULL)?wcslen(ComputerDn):0,
  1883. (MemberDn != NULL)?wcslen(MemberDn):0)
  1884. + MAX_PATH)
  1885. * sizeof(WCHAR));
  1886. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  1887. if (MemberName != NULL) {
  1888. MemberDn = ExtendDn(ReplicaSetDn, MemberName);
  1889. } else {
  1890. //
  1891. // Use computerdn to get the memberdn.
  1892. //
  1893. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  1894. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  1895. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1896. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1897. goto CLEANUP;
  1898. }
  1899. NoOfMembers = FrsSearchContext.EntriesInPage;
  1900. if (NoOfMembers == 0) {
  1901. printf("Error creating subscriber; member not found.\n");
  1902. LdapSearchClose(&FrsSearchContext);
  1903. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1904. goto CLEANUP;
  1905. }
  1906. if (NoOfMembers > 1) {
  1907. printf("Error creating subscriber; duplicate members found.\n");
  1908. LdapSearchClose(&FrsSearchContext);
  1909. Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE;
  1910. goto CLEANUP;
  1911. }
  1912. //
  1913. // Scan the entries returned from ldap_search
  1914. //
  1915. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1916. LdapEntry != NULL;
  1917. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1918. MemberDn = FindValue(LdapEntry, ATTR_DN);
  1919. }
  1920. LdapSearchClose(&FrsSearchContext);
  1921. }
  1922. DPRINT1("MemberDn:%ws\n", MemberDn);
  1923. if (ComputerDn == NULL) {
  1924. //
  1925. // Use MemberDn to find the computerDn. We will come here
  1926. // only if MemberName is supplied but computerdn is not.
  1927. //
  1928. if (!LdapSearchInit(pLdap, MemberDn, LDAP_SCOPE_BASE, NULL,
  1929. MemberAttrs, 0, &FrsSearchContext, FALSE)) {
  1930. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1931. goto CLEANUP;
  1932. }
  1933. NoOfMembers = FrsSearchContext.EntriesInPage;
  1934. if (NoOfMembers == 0) {
  1935. printf("Error creating subscriber; member not found.\n");
  1936. LdapSearchClose(&FrsSearchContext);
  1937. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1938. goto CLEANUP;
  1939. }
  1940. //
  1941. // Scan the entries returned from ldap_search
  1942. //
  1943. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1944. LdapEntry != NULL;
  1945. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1946. LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  1947. if (LocalComputerDn == NULL) {
  1948. printf("Error creating subscriber; computerdn not found.\n");
  1949. LdapSearchClose(&FrsSearchContext);
  1950. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1951. goto CLEANUP;
  1952. }
  1953. }
  1954. LdapSearchClose(&FrsSearchContext);
  1955. } else {
  1956. LocalComputerDn = FrsWcsDup(ComputerDn);
  1957. }
  1958. //
  1959. // We have the computerdn and the memberdn. Now check if a subscriber
  1960. // already exists.
  1961. //
  1962. WCS_CAT7(SearchFilter, L"(&(", ATTR_MEMBER_REF, L"=", MemberDn, L")" , CLASS_SUBSCRIBER, L")");
  1963. if (!LdapSearchInit(pLdap, LocalComputerDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  1964. SubscriberAttrs, 0, &FrsSearchContext, FALSE)) {
  1965. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  1966. goto CLEANUP;
  1967. }
  1968. NoOfSubscribers = FrsSearchContext.EntriesInPage;
  1969. if (NoOfSubscribers > 1) {
  1970. printf("Error creating subscriber; duplicate found.\n");
  1971. LdapSearchClose(&FrsSearchContext);
  1972. Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE;
  1973. goto CLEANUP;
  1974. }
  1975. if (NoOfSubscribers == 1) {
  1976. //
  1977. // Scan the entries returned from ldap_search
  1978. //
  1979. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  1980. LdapEntry != NULL;
  1981. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  1982. SubscriberDn = FindValue(LdapEntry, ATTR_DN);
  1983. }
  1984. Status = UpdateSubscriber(SubscriberDn, MemberDn, RootPath, StagePath);
  1985. } else {
  1986. //
  1987. // Create the new subscriber.
  1988. //
  1989. SubscriptionDn = ExtendDn(LocalComputerDn, MKDSOE_SUBSCRIPTION);
  1990. // ATTR_DN
  1991. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  1992. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  1993. if (WorkingPath != NULL) {
  1994. // ATTR_WORKING_PATH
  1995. AddMod(ATTR_REPLICA_STAGE, WorkingPath, &Mod);
  1996. DPRINT1(" FrsWorkingPath:%ws\n", WorkingPath);
  1997. } else {
  1998. fprintf(stderr, "WARNING: Creating subscription '%ws' with no working path\n", MKDSOE_SUBSCRIPTION);
  1999. }
  2000. if (bDebugMode) {
  2001. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  2002. } else {
  2003. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  2004. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  2005. printf("ERROR - Can't create %ws: %ws\n",
  2006. SubscriptionDn, ldap_err2string(LStatus));
  2007. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2008. goto CLEANUP;
  2009. }
  2010. }
  2011. FreeMod(&Mod);
  2012. //
  2013. // If this member is to be added using the Win2K DFS naming convention
  2014. // then we need to create a few more subscription containers. E.G.
  2015. //
  2016. // (cn=software$|packages, frs subscriber (DFS junction)
  2017. // cn=software$, frs subscription (DFS Root)
  2018. // cn=56421f6a-9edd-4098-a101-bf2e161e4572, frs subscription (domain guid for DFS Guid)
  2019. // cn=dfs volumes, frs subscription
  2020. // cn=ntfrs subscriptions, frs subscription
  2021. // cn=dfs-srv-01, computer object
  2022. // ou=multifunction terminal servers,
  2023. // ou=domain controllers,
  2024. // dc=cps,
  2025. // dc=gov,
  2026. // dc=uk)
  2027. //
  2028. //
  2029. if (bDFSNaming) {
  2030. SaveDn = SubscriptionDn;
  2031. SubscriptionDn = ExtendDn(SubscriptionDn, L"DFS VOLUMES");
  2032. FREE(SaveDn);
  2033. // ATTR_DN
  2034. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  2035. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  2036. if (bDebugMode) {
  2037. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  2038. } else {
  2039. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  2040. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  2041. printf("ERROR - Can't create %ws: %ws\n", SubscriptionDn, ldap_err2string(LStatus));
  2042. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2043. goto CLEANUP;
  2044. }
  2045. }
  2046. FreeMod(&Mod);
  2047. //
  2048. // Add subscription container with name of Domain Guid.
  2049. //
  2050. SaveDn = SubscriptionDn;
  2051. SubscriptionDn = ExtendDn(SubscriptionDn, DomainGuidStr);
  2052. FREE(SaveDn);
  2053. // ATTR_DN
  2054. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  2055. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  2056. if (bDebugMode) {
  2057. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  2058. } else {
  2059. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  2060. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  2061. printf("ERROR - Can't create %ws: %ws\n", SubscriptionDn, ldap_err2string(LStatus));
  2062. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2063. goto CLEANUP;
  2064. }
  2065. }
  2066. FreeMod(&Mod);
  2067. if (wcslen(DFSRoot) > 0) {
  2068. //
  2069. // Add subscription container with name of DFS Root.
  2070. //
  2071. SaveDn = SubscriptionDn;
  2072. SubscriptionDn = ExtendDn(SubscriptionDn, DFSRoot);
  2073. FREE(SaveDn);
  2074. // ATTR_DN
  2075. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  2076. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  2077. if (bDebugMode) {
  2078. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  2079. } else {
  2080. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  2081. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  2082. printf("ERROR - Can't create %ws: %ws\n", SubscriptionDn, ldap_err2string(LStatus));
  2083. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2084. goto CLEANUP;
  2085. }
  2086. }
  2087. FreeMod(&Mod);
  2088. if (wcslen(DFSJunction) > 0) {
  2089. //
  2090. // Add subscription container with name of DFS Junction.
  2091. //
  2092. SaveDn = SubscriptionDn;
  2093. SubscriptionDn = ExtendDn(SubscriptionDn, DFSJunction);
  2094. FREE(SaveDn);
  2095. // ATTR_DN
  2096. DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
  2097. AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
  2098. if (bDebugMode) {
  2099. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
  2100. } else {
  2101. LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
  2102. if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
  2103. printf("ERROR - Can't create %ws: %ws\n", SubscriptionDn, ldap_err2string(LStatus));
  2104. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2105. goto CLEANUP;
  2106. }
  2107. }
  2108. FreeMod(&Mod);
  2109. }
  2110. }
  2111. }
  2112. //
  2113. // Now construct the subscriber object.
  2114. //
  2115. SubscriberDn = ExtendDn(SubscriptionDn, ReplicaSetName);
  2116. // ATTR_DN
  2117. DPRINT1("SubscriberDn:%ws\n", SubscriberDn);
  2118. AddMod(ATTR_CLASS, ATTR_SUBSCRIBER, &Mod);
  2119. // ATTR_MEMBER_REF
  2120. AddMod(ATTR_MEMBER_REF, MemberDn, &Mod);
  2121. DPRINT1(" FrsMemberReference:%ws\n", MemberDn);
  2122. // ATTR_REPLICA_ROOT
  2123. AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
  2124. DPRINT1(" FrsRootPath:%ws\n", RootPath);
  2125. // ATTR_REPLICA_STAGE
  2126. AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
  2127. DPRINT1(" FrsStagePath:%ws\n", StagePath);
  2128. if (bDebugMode) {
  2129. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriberDn);
  2130. } else {
  2131. LStatus = ldap_add_s(pLdap, SubscriberDn, Mod);
  2132. if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
  2133. //
  2134. // prepare the server hint. Needed in case the member object
  2135. // is just created on another DC than the one on which the
  2136. // subscriber is being created.
  2137. //
  2138. LDAPControl simpleControl;
  2139. PLDAPControl controlArray[2];
  2140. INT rc;
  2141. BERVAL* pBerVal = NULL;
  2142. BerElement* pBer;
  2143. pBer = ber_alloc_t(LBER_USE_DER);
  2144. if (!pBer)
  2145. {
  2146. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2147. goto CLEANUP;
  2148. }
  2149. DPRINT1("Sending binding DC Name %ws\n",RefDCName);
  2150. rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
  2151. if ( rc == -1 ) {
  2152. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2153. goto CLEANUP;
  2154. }
  2155. rc = ber_flatten(pBer, &pBerVal);
  2156. if (rc == -1)
  2157. {
  2158. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2159. goto CLEANUP;
  2160. }
  2161. ber_free(pBer,1);
  2162. controlArray[0] = &simpleControl;
  2163. controlArray[1] = NULL;
  2164. // simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
  2165. simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
  2166. simpleControl.ldctl_iscritical = TRUE;
  2167. simpleControl.ldctl_value = *pBerVal;
  2168. LStatus = ldap_add_ext_s(pLdap,
  2169. SubscriberDn,
  2170. Mod,
  2171. (PLDAPControl *)&controlArray, //ServerControls,
  2172. NULL //ClientControls,
  2173. );
  2174. }
  2175. if (LStatus == LDAP_ALREADY_EXISTS) {
  2176. //
  2177. // If the object already exists then convert the create to an update.
  2178. // This is to allow the user to run the data file with creates twice without
  2179. // generating errors but only fixing the objects that have changed.
  2180. //
  2181. Status = UpdateSubscriber(SubscriberDn, MemberDn, RootPath, StagePath);
  2182. } else if (LStatus != LDAP_SUCCESS) {
  2183. DPRINT2("ERROR - Can't create %ws: %ws\n",
  2184. SubscriberDn, ldap_err2string(LStatus));
  2185. Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
  2186. }
  2187. }
  2188. }
  2189. LdapSearchClose(&FrsSearchContext);
  2190. CLEANUP:
  2191. FreeMod(&Mod);
  2192. FREE(ReplicaSetDn);
  2193. FREE(MemberDn);
  2194. FREE(SubscriberDn);
  2195. FREE(SubscriptionDn);
  2196. FREE(SearchFilter);
  2197. FREE(LocalComputerDn);
  2198. FREE(DFSRoot);
  2199. return Status;
  2200. }
  2201. DWORD
  2202. DeleteReplicaMember(
  2203. PWCHAR NTFRSSettingsDn,
  2204. PWCHAR ReplicaSetName,
  2205. PWCHAR MemberName,
  2206. PWCHAR ComputerDn
  2207. )
  2208. /*++
  2209. Routine Description:
  2210. Delete the replica member.
  2211. Arguments:
  2212. Return Value:
  2213. --*/
  2214. {
  2215. LDAPMod **Mod = NULL;
  2216. DWORD LStatus = LDAP_SUCCESS;
  2217. DWORD Status = MKDSOE_SUCCESS;
  2218. PWCHAR ReplicaSetDn = NULL;
  2219. PWCHAR MemberDn = NULL;
  2220. PWCHAR MemberCn = NULL;
  2221. PWCHAR ComputerRef = NULL;
  2222. PWCHAR Attrs[5];
  2223. PLDAPMessage LdapEntry = NULL;
  2224. PWCHAR SearchFilter = NULL;
  2225. DWORD NoOfMembers;
  2226. BOOL bNeedsUpdate = FALSE;
  2227. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  2228. MK_ATTRS_4(Attrs, ATTR_DN, ATTR_CN, ATTR_COMPUTER_REF, ATTR_SERVER_REF);
  2229. SearchFilter = (PWCHAR) malloc((((ComputerDn != NULL)?wcslen(ComputerDn):0)
  2230. + MAX_PATH)
  2231. * sizeof(WCHAR));
  2232. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  2233. if (MemberName != NULL) {
  2234. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", MemberName, L")" , CLASS_MEMBER, L")");
  2235. } else if (ComputerDn != NULL){
  2236. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  2237. } else {
  2238. wcscpy(SearchFilter, CLASS_MEMBER);
  2239. }
  2240. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  2241. Attrs, 0, &FrsSearchContext, FALSE)) {
  2242. Status = MKDSOE_MEMBER_DELETE_FAILED;
  2243. goto CLEANUP;
  2244. }
  2245. NoOfMembers = FrsSearchContext.EntriesInPage;
  2246. if ((NoOfMembers > 1) && (bAffectAll != TRUE)) {
  2247. DPRINT0("Duplicate members found. Deleting all.\n");
  2248. LdapSearchClose(&FrsSearchContext);
  2249. Status = MKDSOE_MEMBER_DUPS_FOUND_DELETE;
  2250. goto CLEANUP;
  2251. }
  2252. if (NoOfMembers != 0) {
  2253. //
  2254. // Scan the entries returned from ldap_search
  2255. //
  2256. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  2257. LdapEntry != NULL;
  2258. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  2259. MemberDn = FindValue(LdapEntry, ATTR_DN);
  2260. MemberCn = FindValue(LdapEntry, ATTR_CN);
  2261. ComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  2262. //
  2263. // If asked to delete the corresponding subscriber then do that first.
  2264. //
  2265. if (bDelSubscriber && ((ComputerRef != NULL) || (ComputerDn != NULL))) {
  2266. Status = DeleteSubscriber(NTFRSSettingsDn, ReplicaSetName,
  2267. MemberCn,
  2268. (ComputerRef != NULL)?ComputerRef:ComputerDn);
  2269. if (Status != MKDSOE_SUCCESS) {
  2270. LdapSearchClose(&FrsSearchContext);
  2271. goto CLEANUP;
  2272. }
  2273. }
  2274. DPRINT1("Deleting Dn:%ws\n", MemberDn);
  2275. if (bDebugMode) {
  2276. DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", MemberDn);
  2277. } else {
  2278. LStatus = ldap_delete_s(pLdap, MemberDn);
  2279. if (LStatus != LDAP_SUCCESS) {
  2280. DPRINT2("ERROR - Can't delete %ws: %ws\n",
  2281. MemberDn, ldap_err2string(LStatus));
  2282. Status = MKDSOE_MEMBER_DELETE_FAILED;
  2283. }
  2284. }
  2285. FREE(MemberDn);
  2286. FREE(MemberCn);
  2287. FREE(ComputerRef);
  2288. }
  2289. } else {
  2290. DPRINT0("Warning deleting; member not found.\n");
  2291. Status = MKDSOE_MEMBER_NOT_FOUND_DELETE;
  2292. }
  2293. LdapSearchClose(&FrsSearchContext);
  2294. CLEANUP:
  2295. FreeMod(&Mod);
  2296. FREE(ReplicaSetDn);
  2297. FREE(MemberDn);
  2298. FREE(MemberCn);
  2299. FREE(ComputerRef);
  2300. FREE(SearchFilter);
  2301. return Status;
  2302. }
  2303. DWORD
  2304. UpdateReplicaMember(
  2305. PWCHAR NTFRSSettingsDn,
  2306. PWCHAR ReplicaSetName,
  2307. PWCHAR MemberName,
  2308. PWCHAR ComputerDn,
  2309. PWCHAR ServerRef,
  2310. PWCHAR RefDCName
  2311. )
  2312. /*++
  2313. Routine Description:
  2314. Update the replica member parameters.
  2315. Arguments:
  2316. Return Value:
  2317. --*/
  2318. {
  2319. LDAPMod **Mod = NULL;
  2320. DWORD LStatus = LDAP_SUCCESS;
  2321. DWORD Status = MKDSOE_SUCCESS;
  2322. PWCHAR ReplicaSetDn = NULL;
  2323. PWCHAR MemberDn = NULL;
  2324. PWCHAR Attrs[4];
  2325. PLDAPMessage LdapEntry = NULL;
  2326. PWCHAR SearchFilter = NULL;
  2327. PWCHAR CurComputerRef = NULL;
  2328. PWCHAR CurServerRef = NULL;
  2329. DWORD NoOfMembers;
  2330. BOOL bNeedsUpdate = FALSE;
  2331. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  2332. MK_ATTRS_3(Attrs, ATTR_DN, ATTR_COMPUTER_REF, ATTR_SERVER_REF);
  2333. SearchFilter = (PWCHAR) malloc((((ComputerDn != NULL)?wcslen(ComputerDn):0)
  2334. + MAX_PATH)
  2335. * sizeof(WCHAR));
  2336. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  2337. if (MemberName != NULL) {
  2338. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", MemberName, L")" , CLASS_MEMBER, L")");
  2339. } else {
  2340. WCS_CAT7(SearchFilter, L"(&(", ATTR_COMPUTER_REF, L"=", ComputerDn, L")" , CLASS_MEMBER, L")");
  2341. }
  2342. if (!LdapSearchInit(pLdap, ReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  2343. Attrs, 0, &FrsSearchContext, FALSE)) {
  2344. Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
  2345. goto CLEANUP;
  2346. }
  2347. NoOfMembers = FrsSearchContext.EntriesInPage;
  2348. if (NoOfMembers == 0) {
  2349. DPRINT0("Error updating; member not found.\n");
  2350. LdapSearchClose(&FrsSearchContext);
  2351. Status = MKDSOE_MEMBER_NOT_FOUND_UPDATE;
  2352. goto CLEANUP;
  2353. }
  2354. if (NoOfMembers > 1) {
  2355. DPRINT0("Error updating; duplicate members found.\n");
  2356. LdapSearchClose(&FrsSearchContext);
  2357. Status = MKDSOE_MEMBER_DUPS_FOUND_UPDATE;
  2358. goto CLEANUP;
  2359. }
  2360. //
  2361. // Scan the entries returned from ldap_search
  2362. //
  2363. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  2364. LdapEntry != NULL;
  2365. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  2366. MemberDn = FindValue(LdapEntry, ATTR_DN);
  2367. CurComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  2368. CurServerRef = FindValue(LdapEntry, ATTR_SERVER_REF);
  2369. }
  2370. LdapSearchClose(&FrsSearchContext);
  2371. DPRINT1("MemberDn:%ws\n", MemberDn);
  2372. // Check ATTR_COMPUTER_REF
  2373. // if a ref is supplied then make sure it is same as the current ref.
  2374. // if a ref is not supplied then leave it as it is.
  2375. if (ComputerDn != NULL) {
  2376. if ((CurComputerRef == NULL) ||
  2377. ((CurComputerRef != NULL) && wcscmp(ComputerDn, CurComputerRef))) {
  2378. AddMod(ATTR_COMPUTER_REF, ComputerDn, &Mod);
  2379. bNeedsUpdate = TRUE;
  2380. DPRINT1(" New FrsComputerReference:%ws\n", ComputerDn);
  2381. }
  2382. }
  2383. // Check ATTR_SERVER_REF
  2384. // if a ref is supplied then make sure it is same as the current ref.
  2385. // if a ref is not supplied then leave it as it is.
  2386. if (ServerRef != NULL) {
  2387. if ((CurServerRef == NULL) ||
  2388. ((CurServerRef != NULL) && wcscmp(ServerRef, CurServerRef))) {
  2389. AddMod(ATTR_SERVER_REF, ServerRef, &Mod);
  2390. bNeedsUpdate = TRUE;
  2391. DPRINT1(" New ServerReference:%ws\n", ServerRef);
  2392. }
  2393. }
  2394. if (bNeedsUpdate) {
  2395. if (bDebugMode) {
  2396. DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", MemberDn);
  2397. } else {
  2398. LStatus = ldap_modify_s(pLdap, MemberDn, Mod);
  2399. if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
  2400. //
  2401. // prepare the server hint. Needed in case the member object
  2402. // is just created on another DC than the one on which the
  2403. // subscriber is being created.
  2404. //
  2405. LDAPControl simpleControl;
  2406. PLDAPControl controlArray[2];
  2407. INT rc;
  2408. BERVAL* pBerVal = NULL;
  2409. BerElement* pBer;
  2410. pBer = ber_alloc_t(LBER_USE_DER);
  2411. if (!pBer)
  2412. {
  2413. Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
  2414. goto CLEANUP;
  2415. }
  2416. DPRINT1("Sending binding DC Name %ws\n",RefDCName);
  2417. rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
  2418. if ( rc == -1 ) {
  2419. Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
  2420. goto CLEANUP;
  2421. }
  2422. rc = ber_flatten(pBer, &pBerVal);
  2423. if (rc == -1)
  2424. {
  2425. Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
  2426. goto CLEANUP;
  2427. }
  2428. ber_free(pBer,1);
  2429. controlArray[0] = &simpleControl;
  2430. controlArray[1] = NULL;
  2431. // simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
  2432. simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
  2433. simpleControl.ldctl_iscritical = TRUE;
  2434. simpleControl.ldctl_value = *pBerVal;
  2435. LStatus = ldap_modify_ext_s(pLdap,
  2436. MemberDn,
  2437. Mod,
  2438. (PLDAPControl *)&controlArray, //ServerControls,
  2439. NULL //ClientControls,
  2440. );
  2441. }
  2442. if (LStatus != LDAP_SUCCESS) {
  2443. DPRINT2("ERROR - Can't update %ws: %ws\n",
  2444. MemberDn, ldap_err2string(LStatus));
  2445. Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
  2446. }
  2447. }
  2448. } else {
  2449. DPRINT0("No update required\n");
  2450. }
  2451. if (bMakeMePrimary && (Status == MKDSOE_SUCCESS)) {
  2452. //
  2453. // Update the primary member attribute on the replica set object to
  2454. // reference this member if /makemeprimary is set.
  2455. //
  2456. Status = UpdateReplicaSet(NTFRSSettingsDn, ReplicaSetName,
  2457. NULL, NULL, NULL, MemberName, NULL);
  2458. }
  2459. CLEANUP:
  2460. FreeMod(&Mod);
  2461. FREE(ReplicaSetDn);
  2462. FREE(MemberDn);
  2463. FREE(SearchFilter);
  2464. FREE(CurComputerRef);
  2465. FREE(CurServerRef);
  2466. return Status;
  2467. }
  2468. DWORD
  2469. CreateNewReplicaMember(
  2470. PWCHAR NTFRSSettingsDn,
  2471. PWCHAR ReplicaSetName,
  2472. PWCHAR MemberName,
  2473. PWCHAR ComputerDn,
  2474. PWCHAR ServerRef,
  2475. PWCHAR RefDCName
  2476. )
  2477. /*++
  2478. Routine Description:
  2479. Create a new replica member.
  2480. Arguments:
  2481. Return Value:
  2482. --*/
  2483. {
  2484. LDAPMod **Mod = NULL;
  2485. DWORD LStatus = LDAP_SUCCESS;
  2486. DWORD Status = MKDSOE_SUCCESS;
  2487. PWCHAR ReplicaSetDn = NULL;
  2488. PWCHAR MemberDn = NULL;
  2489. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  2490. MemberDn = ExtendDn(ReplicaSetDn, MemberName);
  2491. // ATTR_DN
  2492. DPRINT1("MemberDn:%ws\n", MemberDn);
  2493. AddMod(ATTR_CLASS, ATTR_MEMBER, &Mod);
  2494. // ATTR_COMPUTER_REF
  2495. if (ComputerDn != NULL) {
  2496. AddMod(ATTR_COMPUTER_REF, ComputerDn, &Mod);
  2497. DPRINT1(" FrsComputerReference:%ws\n", ComputerDn);
  2498. }
  2499. // ATTR_SERVER_REF
  2500. if (ServerRef != NULL) {
  2501. AddMod(ATTR_SERVER_REF, ServerRef, &Mod);
  2502. DPRINT1(" ServerReference:%ws\n", ServerRef);
  2503. }
  2504. if (bDebugMode) {
  2505. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", MemberDn);
  2506. } else {
  2507. LStatus = ldap_add_s(pLdap, MemberDn, Mod);
  2508. if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
  2509. //
  2510. // prepare the server hint. Needed in case the member object
  2511. // is just created on another DC than the one on which the
  2512. // subscriber is being created.
  2513. //
  2514. LDAPControl simpleControl;
  2515. PLDAPControl controlArray[2];
  2516. INT rc;
  2517. BERVAL* pBerVal = NULL;
  2518. BerElement* pBer;
  2519. pBer = ber_alloc_t(LBER_USE_DER);
  2520. if (!pBer) {
  2521. Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
  2522. goto CLEANUP;
  2523. }
  2524. DPRINT1("Sending binding DC Name %ws\n",RefDCName);
  2525. rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
  2526. if ( rc == -1 ) {
  2527. Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
  2528. goto CLEANUP;
  2529. }
  2530. rc = ber_flatten(pBer, &pBerVal);
  2531. if (rc == -1) {
  2532. Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
  2533. goto CLEANUP;
  2534. }
  2535. ber_free(pBer,1);
  2536. controlArray[0] = &simpleControl;
  2537. controlArray[1] = NULL;
  2538. // simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
  2539. simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
  2540. simpleControl.ldctl_iscritical = TRUE;
  2541. simpleControl.ldctl_value = *pBerVal;
  2542. LStatus = ldap_add_ext_s(pLdap,
  2543. MemberDn,
  2544. Mod,
  2545. (PLDAPControl *)&controlArray, //ServerControls,
  2546. NULL //ClientControls,
  2547. );
  2548. }
  2549. if (LStatus == LDAP_ALREADY_EXISTS) {
  2550. //
  2551. // If the object already exists then convert the create to an update.
  2552. // This is to allow the user to run the data file with creates twice without
  2553. // generating errors but only fixing the objects that have changed.
  2554. //
  2555. Status = UpdateReplicaMember(NTFRSSettingsDn,
  2556. ReplicaSetName,
  2557. MemberName,
  2558. ComputerDn,
  2559. ServerRef,
  2560. RefDCName);
  2561. } else if (LStatus != LDAP_SUCCESS) {
  2562. DPRINT2("ERROR - Can't create %ws: %ws\n", MemberDn, ldap_err2string(LStatus));
  2563. Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
  2564. } else if (bMakeMePrimary) {
  2565. //
  2566. // Update the primary member attribute on the replica set object to
  2567. // reference this member if /makemeprimary is set.
  2568. //
  2569. Status = UpdateReplicaSet(NTFRSSettingsDn, ReplicaSetName,
  2570. NULL, NULL, NULL, MemberName, NULL);
  2571. }
  2572. }
  2573. CLEANUP:
  2574. FreeMod(&Mod);
  2575. FREE(ReplicaSetDn);
  2576. FREE(MemberDn);
  2577. return Status;
  2578. }
  2579. DWORD
  2580. DeleteReplicaSet(
  2581. PWCHAR NTFRSSettingsDn,
  2582. PWCHAR ReplicaSetName
  2583. )
  2584. /*++
  2585. Routine Description:
  2586. delete replica set.
  2587. Arguments:
  2588. Return Value:
  2589. --*/
  2590. {
  2591. LDAPMod **Mod = NULL;
  2592. DWORD LStatus = LDAP_SUCCESS;
  2593. DWORD Status = MKDSOE_SUCCESS;
  2594. PWCHAR ReplicaSetDn = NULL;
  2595. PWCHAR Attrs[2];
  2596. PLDAPMessage LdapEntry = NULL;
  2597. WCHAR SearchFilter[MAX_PATH];
  2598. DWORD NoOfSets;
  2599. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  2600. MK_ATTRS_1(Attrs, ATTR_DN);
  2601. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", ReplicaSetName, L")" , CLASS_NTFRS_REPLICA_SET, L")");
  2602. if (!LdapSearchInit(pLdap, NTFRSSettingsDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  2603. Attrs, 0, &FrsSearchContext, FALSE)) {
  2604. Status = MKDSOE_SET_DELETE_FAILED;
  2605. goto CLEANUP;
  2606. }
  2607. NoOfSets = FrsSearchContext.EntriesInPage;
  2608. if (NoOfSets == 0) {
  2609. DPRINT0("Error deleting; connection not found.\n");
  2610. LdapSearchClose(&FrsSearchContext);
  2611. Status = MKDSOE_SET_NOT_FOUND_DELETE;
  2612. goto CLEANUP;
  2613. }
  2614. if (NoOfSets > 1) {
  2615. DPRINT0("Error deleting; duplicate sets found.\n");
  2616. LdapSearchClose(&FrsSearchContext);
  2617. Status = MKDSOE_SET_DUPS_FOUND_DELETE;
  2618. goto CLEANUP;
  2619. }
  2620. //
  2621. // Scan the entries returned from ldap_search
  2622. //
  2623. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  2624. LdapEntry != NULL;
  2625. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  2626. ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
  2627. DPRINT1("Deleting Dn:%ws\n", ReplicaSetDn);
  2628. if (bDebugMode) {
  2629. DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", ReplicaSetDn);
  2630. } else {
  2631. LStatus = ldap_delete_s(pLdap, ReplicaSetDn);
  2632. if (LStatus != LDAP_SUCCESS) {
  2633. DPRINT2("ERROR - Can't delete %ws: %ws\n",
  2634. ReplicaSetDn, ldap_err2string(LStatus));
  2635. Status = MKDSOE_SET_DELETE_FAILED;
  2636. }
  2637. }
  2638. }
  2639. LdapSearchClose(&FrsSearchContext);
  2640. CLEANUP:
  2641. FreeMod(&Mod);
  2642. FREE(ReplicaSetDn);
  2643. return Status;
  2644. }
  2645. DWORD
  2646. UpdateReplicaSet(
  2647. PWCHAR NTFRSSettingsDn,
  2648. PWCHAR ReplicaSetName,
  2649. PWCHAR ReplicaSetType,
  2650. PWCHAR FileFilter,
  2651. PWCHAR DirectoryFilter,
  2652. PWCHAR PrimaryMember,
  2653. PBYTE pSchedule
  2654. )
  2655. /*++
  2656. Routine Description:
  2657. Update the replica set parameters.
  2658. Arguments:
  2659. Return Value:
  2660. --*/
  2661. {
  2662. LDAPMod **Mod = NULL;
  2663. DWORD LStatus = LDAP_SUCCESS;
  2664. DWORD Status = MKDSOE_SUCCESS;
  2665. PWCHAR ReplicaSetDn = NULL;
  2666. PWCHAR Attrs[7];
  2667. PLDAPMessage LdapEntry = NULL;
  2668. WCHAR SearchFilter[MAX_PATH];
  2669. PWCHAR CurSetType = NULL;
  2670. PWCHAR CurFileFilter = NULL;
  2671. PWCHAR CurDirectoryFilter = NULL;
  2672. PWCHAR CurPrimaryMember = NULL;
  2673. PWCHAR PrimaryMemberDn = NULL;
  2674. DWORD NoOfSets;
  2675. PSCHEDULE Schedule = NULL;
  2676. DWORD ScheduleLen;
  2677. BOOL bNeedsUpdate = FALSE;
  2678. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  2679. MK_ATTRS_6(Attrs, ATTR_DN, ATTR_SET_TYPE, ATTR_FILE_FILTER, ATTR_DIRECTORY_FILTER, ATTR_SCHEDULE, ATTR_PRIMARY_MEMBER);
  2680. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", ReplicaSetName, L")" , CLASS_NTFRS_REPLICA_SET, L")");
  2681. if (!LdapSearchInit(pLdap, NTFRSSettingsDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  2682. Attrs, 0, &FrsSearchContext, FALSE)) {
  2683. Status = MKDSOE_SET_OBJ_UPDATE_FAILED;
  2684. goto CLEANUP;
  2685. }
  2686. NoOfSets = FrsSearchContext.EntriesInPage;
  2687. if (NoOfSets == 0) {
  2688. DPRINT0("Error updating; connection not found.\n");
  2689. LdapSearchClose(&FrsSearchContext);
  2690. Status = MKDSOE_SET_NOT_FOUND_UPDATE;
  2691. goto CLEANUP;
  2692. }
  2693. if (NoOfSets > 1) {
  2694. DPRINT0("Error updating; duplicate connections found.\n");
  2695. LdapSearchClose(&FrsSearchContext);
  2696. Status = MKDSOE_SET_DUPS_FOUND_UPDATE;
  2697. goto CLEANUP;
  2698. }
  2699. //
  2700. // Scan the entries returned from ldap_search
  2701. //
  2702. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  2703. LdapEntry != NULL;
  2704. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  2705. ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
  2706. CurSetType = FindValue(LdapEntry, ATTR_SET_TYPE);
  2707. CurFileFilter = FindValue(LdapEntry, ATTR_FILE_FILTER);
  2708. CurDirectoryFilter = FindValue(LdapEntry, ATTR_DIRECTORY_FILTER);
  2709. CurPrimaryMember = FindValue(LdapEntry, ATTR_PRIMARY_MEMBER);
  2710. FindBerValue(LdapEntry, ATTR_SCHEDULE, &ScheduleLen, (VOID **)&Schedule);
  2711. }
  2712. LdapSearchClose(&FrsSearchContext);
  2713. DPRINT1("ReplicaSetDn:%ws\n", ReplicaSetDn);
  2714. // Check ATTR_SET_TYPE
  2715. // if a type is supplied then make sure it is same as the current type.
  2716. // if a type is not supplied then leave it as it is.
  2717. if (ReplicaSetType != NULL) {
  2718. if ((CurSetType == NULL) ||
  2719. ((CurSetType != NULL) && wcscmp(ReplicaSetType, CurSetType))) {
  2720. AddMod(ATTR_SET_TYPE, ReplicaSetType, &Mod);
  2721. bNeedsUpdate = TRUE;
  2722. DPRINT1(" New FrsReplicaSetType:%ws\n", ReplicaSetType);
  2723. }
  2724. }
  2725. // Check ATTR_FILE_FILTER
  2726. // if a filter is supplied then make sure it is same as the current filter.
  2727. // if a filter is not supplied then leave it as it is.
  2728. if (FileFilter != NULL) {
  2729. if ((CurFileFilter == NULL) ||
  2730. ((CurFileFilter != NULL) && wcscmp(FileFilter, CurFileFilter))) {
  2731. AddMod(ATTR_FILE_FILTER, FileFilter, &Mod);
  2732. bNeedsUpdate = TRUE;
  2733. DPRINT1(" New FrsFileFilter:%ws\n", FileFilter);
  2734. }
  2735. }
  2736. // Check ATTR_DIRECTORY_FILTER
  2737. // if a filter is supplied then make sure it is same as the current filter.
  2738. // if a filter is not supplied then leave it as it is.
  2739. if (DirectoryFilter != NULL) {
  2740. if ((CurDirectoryFilter == NULL) ||
  2741. ((CurDirectoryFilter != NULL) && wcscmp(DirectoryFilter, CurDirectoryFilter))) {
  2742. AddMod(ATTR_DIRECTORY_FILTER, DirectoryFilter, &Mod);
  2743. bNeedsUpdate = TRUE;
  2744. DPRINT1(" New FrsDirectoryFilter:%ws\n", DirectoryFilter);
  2745. }
  2746. }
  2747. // Check ATTR_PRIMARY_MEMBER
  2748. // if a PrimaryMember is supplied then make sure it is same as the current PrimaryMember.
  2749. // if a PrimaryMember is not supplied then leave it as it is.
  2750. if (PrimaryMember != NULL) {
  2751. PrimaryMemberDn = ExtendDn(ReplicaSetDn, PrimaryMember);
  2752. if ((CurPrimaryMember == NULL) ||
  2753. ((CurPrimaryMember != NULL) && wcscmp(PrimaryMemberDn, CurPrimaryMember))) {
  2754. AddMod(ATTR_PRIMARY_MEMBER, PrimaryMemberDn, &Mod);
  2755. bNeedsUpdate = TRUE;
  2756. DPRINT1(" New FrsPrimaryMember:%ws\n", PrimaryMemberDn);
  2757. }
  2758. }
  2759. // Check ATTR_SCHEDULE
  2760. if (pSchedule != NULL) {
  2761. if ((Schedule == NULL) ||
  2762. (FRST_SIZE_OF_SCHEDULE != ScheduleLen) ||
  2763. (memcmp(Schedule, pSchedule, FRST_SIZE_OF_SCHEDULE))) {
  2764. bNeedsUpdate = TRUE;
  2765. AddBerMod(ATTR_SCHEDULE,(PCHAR)pSchedule,FRST_SIZE_OF_SCHEDULE,&Mod);
  2766. DPRINT0(" New schedule:\n");
  2767. PrintSchedule((PSCHEDULE)pSchedule, 0x0F);
  2768. }
  2769. }
  2770. if (bNeedsUpdate) {
  2771. if (bDebugMode) {
  2772. DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", ReplicaSetDn);
  2773. } else {
  2774. LStatus = ldap_modify_s(pLdap, ReplicaSetDn, Mod);
  2775. if (LStatus != LDAP_SUCCESS) {
  2776. DPRINT2("ERROR - Can't update %ws: %ws\n",
  2777. ReplicaSetDn, ldap_err2string(LStatus));
  2778. Status = MKDSOE_SET_OBJ_UPDATE_FAILED;
  2779. }
  2780. }
  2781. } else {
  2782. DPRINT0("No update required\n");
  2783. }
  2784. CLEANUP:
  2785. FreeMod(&Mod);
  2786. FREE(ReplicaSetDn);
  2787. FREE(PrimaryMemberDn);
  2788. FREE(CurSetType);
  2789. FREE(CurFileFilter);
  2790. FREE(CurDirectoryFilter);
  2791. FREE(CurPrimaryMember);
  2792. FREE(Schedule);
  2793. return Status;
  2794. }
  2795. DWORD
  2796. CreateNewReplicaSet(
  2797. PWCHAR NTFRSSettingsDn,
  2798. PWCHAR ReplicaSetName,
  2799. PWCHAR ReplicaSetType,
  2800. PWCHAR FileFilter,
  2801. PWCHAR DirectoryFilter,
  2802. PWCHAR PrimaryMember,
  2803. PBYTE pSchedule
  2804. )
  2805. /*++
  2806. Routine Description:
  2807. Create a new replica Set.
  2808. Arguments:
  2809. Return Value:
  2810. --*/
  2811. {
  2812. LDAPMod **Mod = NULL;
  2813. DWORD LStatus = LDAP_SUCCESS;
  2814. DWORD Status = MKDSOE_SUCCESS;
  2815. PWCHAR ReplicaSetDn = NULL;
  2816. PWCHAR PrimaryMemberDn = NULL;
  2817. UINT i;
  2818. ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
  2819. // ATTR_DN
  2820. DPRINT1("ReplicaSetDn:%ws\n", ReplicaSetDn);
  2821. AddMod(ATTR_CLASS, ATTR_REPLICA_SET, &Mod);
  2822. // ATTR_SET_TYPE
  2823. AddMod(ATTR_SET_TYPE, ReplicaSetType, &Mod);
  2824. DPRINT1(" FrsReplicaSetType:%ws\n", ReplicaSetType);
  2825. // ATTR_FILE_FILTER
  2826. if (FileFilter != NULL) {
  2827. AddMod(ATTR_FILE_FILTER, FileFilter, &Mod);
  2828. DPRINT1(" FrsFileFilter:%ws\n", FileFilter);
  2829. }
  2830. // ATTR_DIRECTORY_FILTER
  2831. if (DirectoryFilter != NULL) {
  2832. AddMod(ATTR_DIRECTORY_FILTER, DirectoryFilter, &Mod);
  2833. DPRINT1(" FrsDirectoryFilter:%ws\n", DirectoryFilter);
  2834. }
  2835. // ATTR_PRIMARY_MEMBER
  2836. if (PrimaryMember != NULL) {
  2837. PrimaryMemberDn = ExtendDn(ReplicaSetDn, PrimaryMember);
  2838. AddMod(ATTR_PRIMARY_MEMBER, PrimaryMemberDn, &Mod);
  2839. DPRINT1(" FrsPrimaryMemberr:%ws\n", PrimaryMemberDn);
  2840. }
  2841. if (pSchedule != NULL) {
  2842. AddBerMod(ATTR_SCHEDULE,(PCHAR)pSchedule,FRST_SIZE_OF_SCHEDULE,&Mod);
  2843. PrintSchedule((PSCHEDULE)pSchedule, 0x0F);
  2844. }
  2845. if (bDebugMode) {
  2846. DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", ReplicaSetDn);
  2847. } else {
  2848. LStatus = ldap_add_s(pLdap, ReplicaSetDn, Mod);
  2849. if (LStatus == LDAP_ALREADY_EXISTS) {
  2850. //
  2851. // If the object already exists then convert the create to an update.
  2852. // This is to allow the user to run the data file with creates twice without
  2853. // generating errors but only fixing the objects that have changed.
  2854. //
  2855. Status = UpdateReplicaSet(NTFRSSettingsDn,
  2856. ReplicaSetName,
  2857. ReplicaSetType,
  2858. FileFilter,
  2859. DirectoryFilter,
  2860. PrimaryMember,
  2861. pSchedule);
  2862. } else if (LStatus != LDAP_SUCCESS) {
  2863. DPRINT2("ERROR - Can't create %ws: %ws\n",
  2864. ReplicaSetDn, ldap_err2string(LStatus));
  2865. Status = MKDSOE_SET_OBJ_CRE_FAILED;
  2866. }
  2867. }
  2868. FreeMod(&Mod);
  2869. FREE(ReplicaSetDn);
  2870. FREE(PrimaryMemberDn);
  2871. return Status;
  2872. }
  2873. VOID
  2874. PrintScheduleGrid(
  2875. PUCHAR ScheduleData,
  2876. DWORD Mask
  2877. )
  2878. /*++
  2879. Routine Description:
  2880. Print the schedule grid.
  2881. Arguments:
  2882. Schedule
  2883. Mask for each byte.
  2884. Return Value:
  2885. NONE
  2886. --*/
  2887. {
  2888. DWORD Day, Hour;
  2889. for (Day = 0; Day < 7; ++Day) {
  2890. printf(" Day %1d: ",Day + 1);
  2891. for (Hour = 0; Hour < 24; ++Hour) {
  2892. printf("%1x", *(ScheduleData + (Day * 24) + Hour) & Mask);
  2893. }
  2894. printf("\n");
  2895. }
  2896. }
  2897. VOID
  2898. PrintSchedule(
  2899. PSCHEDULE Schedule,
  2900. DWORD Mask
  2901. )
  2902. /*++
  2903. Routine Description:
  2904. Print the schedule.
  2905. Arguments:
  2906. Schedule
  2907. Mask for each byte.
  2908. Return Value:
  2909. NONE
  2910. --*/
  2911. {
  2912. PUCHAR ScheduleData;
  2913. DWORD i;
  2914. if (bVerboseMode) {
  2915. printf(" schedule:\n");
  2916. for (i = 0; i < Schedule->NumberOfSchedules; ++i) {
  2917. ScheduleData = ((PUCHAR)Schedule) + Schedule->Schedules[i].Offset;
  2918. if (Schedule->Schedules[i].Type != SCHEDULE_INTERVAL) {
  2919. continue;
  2920. }
  2921. PrintScheduleGrid(ScheduleData, Mask);
  2922. }
  2923. }
  2924. }
  2925. DWORD
  2926. DumpSubscribers(
  2927. PWCHAR ComputerDn,
  2928. PWCHAR MemberDn
  2929. )
  2930. /*++
  2931. Routine Description:
  2932. Dump the frs member object.
  2933. Arguments:
  2934. Return Value:
  2935. --*/
  2936. {
  2937. DWORD LStatus;
  2938. DWORD Status = MKDSOE_SUCCESS;
  2939. PWCHAR Attrs[5];
  2940. PLDAPMessage LdapEntry = NULL;
  2941. PWCHAR Val = NULL;
  2942. PWCHAR SearchFilter = NULL;
  2943. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  2944. DWORD NoOfSubscribers;
  2945. MK_ATTRS_4(Attrs, ATTR_DN, ATTR_MEMBER_REF, ATTR_REPLICA_ROOT, ATTR_REPLICA_STAGE);
  2946. SearchFilter = (PWCHAR) malloc((((MemberDn != NULL)?wcslen(MemberDn):0)
  2947. + MAX_PATH)
  2948. * sizeof(WCHAR));
  2949. if (MemberDn != NULL) {
  2950. WCS_CAT7(SearchFilter, L"(&(", ATTR_MEMBER_REF, L"=", MemberDn, L")" , CLASS_SUBSCRIBER, L")");
  2951. } else {
  2952. wcscpy(SearchFilter, CLASS_SUBSCRIBER);
  2953. }
  2954. if (!LdapSearchInit(pLdap, ComputerDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  2955. Attrs, 0, &FrsSearchContext, FALSE)) {
  2956. Status = MKDSOE_SUBSCRIBER_DUMP_FAILED;
  2957. goto CLEANUP;
  2958. }
  2959. NoOfSubscribers = FrsSearchContext.EntriesInPage;
  2960. if (NoOfSubscribers == 0) {
  2961. LdapSearchClose(&FrsSearchContext);
  2962. if (MemberDn != NULL) {
  2963. //
  2964. // This error return only makes sense when we were asked to dump
  2965. // a specific subscriber.
  2966. //
  2967. DPRINT0("Error dumping; subscriber not found.\n");
  2968. Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DUMP;
  2969. }
  2970. goto CLEANUP;
  2971. }
  2972. //
  2973. // Scan the entries returned from ldap_search
  2974. //
  2975. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  2976. LdapEntry != NULL;
  2977. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  2978. // ATTR_DN
  2979. Val = FindValue(LdapEntry, ATTR_DN);
  2980. printf("\n SubscriberDn:%ws\n", Val);
  2981. FREE(Val);
  2982. //
  2983. // ATTR_CLASS
  2984. // We know the class
  2985. printf(" ObjectClass:nTFRSSubscriber\n");
  2986. // ATTR_MEMBER_REF
  2987. Val = FindValue(LdapEntry, ATTR_MEMBER_REF);
  2988. printf(" FrsMemberReference:%ws\n", Val);
  2989. FREE(Val);
  2990. // ATTR_REPLICA_ROOT
  2991. Val = FindValue(LdapEntry, ATTR_REPLICA_ROOT);
  2992. printf(" FrsRootPath:%ws\n", Val);
  2993. FREE(Val);
  2994. // ATTR_REPLICA_STAGE
  2995. Val = FindValue(LdapEntry, ATTR_REPLICA_STAGE);
  2996. printf(" FrsStagingPath:%ws\n", Val);
  2997. FREE(Val);
  2998. }
  2999. LdapSearchClose(&FrsSearchContext);
  3000. CLEANUP:
  3001. FREE(SearchFilter);
  3002. return Status;
  3003. }
  3004. DWORD
  3005. DumpReplicaMembers(
  3006. PWCHAR NTFRSReplicaSetDn,
  3007. PWCHAR MemberName
  3008. )
  3009. /*++
  3010. Routine Description:
  3011. Dump the frs member object.
  3012. Arguments:
  3013. Return Value:
  3014. --*/
  3015. {
  3016. DWORD LStatus;
  3017. DWORD Status = MKDSOE_SUCCESS;
  3018. PWCHAR Attrs[4];
  3019. PLDAPMessage LdapEntry = NULL;
  3020. PWCHAR Val = NULL;
  3021. PWCHAR ComputerRef = NULL;
  3022. PWCHAR MemberDn = NULL;
  3023. WCHAR SearchFilter[MAX_PATH];
  3024. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  3025. DWORD NoOfMembers;
  3026. MK_ATTRS_3(Attrs, ATTR_DN, ATTR_COMPUTER_REF, ATTR_SERVER_REF);
  3027. if (MemberName != NULL) {
  3028. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", MemberName, L")" , CLASS_MEMBER, L")");
  3029. } else {
  3030. wcscpy(SearchFilter, CLASS_MEMBER);
  3031. }
  3032. if (!LdapSearchInit(pLdap, NTFRSReplicaSetDn, LDAP_SCOPE_ONELEVEL, SearchFilter,
  3033. Attrs, 0, &FrsSearchContext, FALSE)) {
  3034. Status = MKDSOE_MEMBER_DUMP_FAILED;
  3035. goto CLEANUP;
  3036. }
  3037. NoOfMembers = FrsSearchContext.EntriesInPage;
  3038. if (NoOfMembers == 0) {
  3039. LdapSearchClose(&FrsSearchContext);
  3040. if (MemberName != NULL) {
  3041. //
  3042. // This error return only makes sense when we were asked to dump
  3043. // a specific member object.
  3044. //
  3045. DPRINT0("Error dumping; member not found.\n");
  3046. Status = MKDSOE_MEMBER_NOT_FOUND_DUMP;
  3047. }
  3048. goto CLEANUP;
  3049. }
  3050. //
  3051. // Scan the entries returned from ldap_search
  3052. //
  3053. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  3054. LdapEntry != NULL;
  3055. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  3056. // ATTR_DN
  3057. MemberDn = FindValue(LdapEntry, ATTR_DN);
  3058. printf("\n MemberDn:%ws\n", MemberDn);
  3059. //
  3060. // ATTR_CLASS
  3061. // We know the class
  3062. printf(" ObjectClass:nTFRSMember\n");
  3063. // ATTR_COMPUTER_REF
  3064. ComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
  3065. printf(" FrsComputerReference:%ws\n", ComputerRef);
  3066. // ATTR_SERVER_REF
  3067. Val = FindValue(LdapEntry, ATTR_SERVER_REF);
  3068. printf(" ServerReference:%ws\n", Val);
  3069. FREE(Val);
  3070. if (bAffectAll && ComputerRef != NULL) {
  3071. DumpSubscribers(ComputerRef, MemberDn);
  3072. }
  3073. FREE(ComputerRef);
  3074. FREE(MemberDn);
  3075. }
  3076. LdapSearchClose(&FrsSearchContext);
  3077. CLEANUP:
  3078. return Status;
  3079. }
  3080. DWORD
  3081. DumpReplicaSet(
  3082. PWCHAR NTFRSSettingsDn,
  3083. PWCHAR ReplicaSetName
  3084. )
  3085. /*++
  3086. Routine Description:
  3087. Dump the replica set object.
  3088. Arguments:
  3089. Return Value:
  3090. --*/
  3091. {
  3092. DWORD LStatus;
  3093. DWORD Status = MKDSOE_SUCCESS;
  3094. PWCHAR Attrs[7];
  3095. PLDAPMessage LdapEntry = NULL;
  3096. PWCHAR Val = NULL;
  3097. PWCHAR ReplicaSetDn = NULL;
  3098. WCHAR SearchFilter[MAX_PATH];
  3099. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  3100. DWORD ReplicaSetType;
  3101. DWORD NoOfSets;
  3102. DWORD ScheduleLen;
  3103. PSCHEDULE Schedule = NULL;
  3104. BOOL SaveVerbose;
  3105. MK_ATTRS_6(Attrs, ATTR_DN, ATTR_SET_TYPE, ATTR_FILE_FILTER, ATTR_DIRECTORY_FILTER, ATTR_SCHEDULE, ATTR_PRIMARY_MEMBER);
  3106. if (ReplicaSetName != NULL) {
  3107. WCS_CAT7(SearchFilter, L"(&(", ATTR_CN, L"=", ReplicaSetName, L")" , CLASS_NTFRS_REPLICA_SET, L")");
  3108. } else {
  3109. wcscpy(SearchFilter, CLASS_NTFRS_REPLICA_SET);
  3110. }
  3111. if (!LdapSearchInit(pLdap, NTFRSSettingsDn, LDAP_SCOPE_SUBTREE, SearchFilter,
  3112. Attrs, 0, &FrsSearchContext, FALSE)) {
  3113. Status = MKDSOE_SET_DUMP_FAILED;
  3114. goto CLEANUP;
  3115. }
  3116. NoOfSets = FrsSearchContext.EntriesInPage;
  3117. if (NoOfSets == 0) {
  3118. DPRINT0("Error dumping; replica set not found.\n");
  3119. LdapSearchClose(&FrsSearchContext);
  3120. Status = MKDSOE_SET_NOT_FOUND_DUMP;
  3121. goto CLEANUP;
  3122. }
  3123. //
  3124. // Scan the entries returned from ldap_search
  3125. //
  3126. for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
  3127. LdapEntry != NULL;
  3128. LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
  3129. // ATTR_DN
  3130. ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
  3131. printf("\nReplicaSetDn:%ws\n", ReplicaSetDn);
  3132. //
  3133. // ATTR_CLASS
  3134. // We know the class
  3135. printf(" ObjectClass:nTFRSReplicaSet\n");
  3136. // ATTR_SET_TYPE
  3137. Val = FindValue(LdapEntry, ATTR_SET_TYPE);
  3138. ReplicaSetType = _wtoi(Val);
  3139. printf(" FrsReplicaSetType:%ws ", Val);
  3140. if (ReplicaSetType > MKDSOE_RSTYPE_MAX) {
  3141. printf("[ Invalid Type ");
  3142. } else {
  3143. printf("[ %ws ", ReplicaSetTypeStr[ReplicaSetType]);
  3144. }
  3145. printf("]\n");
  3146. FREE(Val);
  3147. // ATTR_FILE_FILTER
  3148. Val = FindValue(LdapEntry, ATTR_FILE_FILTER);
  3149. printf(" FrsFileFilter:%ws\n", Val);
  3150. FREE(Val);
  3151. // ATTR_DIRECTORY_FILTER
  3152. Val = FindValue(LdapEntry, ATTR_DIRECTORY_FILTER);
  3153. printf(" FrsDirectoryFilter:%ws\n", Val);
  3154. FREE(Val);
  3155. // ATTR_PRIMARY_MEMBER
  3156. Val = FindValue(LdapEntry, ATTR_PRIMARY_MEMBER);
  3157. printf(" FrsPrimaryMember:%ws\n", Val);
  3158. FREE(Val);
  3159. // ATTR_SCHEDULE
  3160. FindBerValue(LdapEntry, ATTR_SCHEDULE, &ScheduleLen, (VOID **)&Schedule);
  3161. if (Schedule) {
  3162. SaveVerbose = bVerboseMode;
  3163. bVerboseMode = TRUE;
  3164. PrintSchedule(Schedule, 0x0F);
  3165. bVerboseMode = SaveVerbose;
  3166. delete(Schedule);
  3167. }
  3168. //
  3169. // Dump the members if asked.
  3170. //
  3171. if (bAffectAll) {
  3172. DumpReplicaMembers(ReplicaSetDn, NULL);
  3173. }
  3174. FREE(ReplicaSetDn);
  3175. }
  3176. LdapSearchClose(&FrsSearchContext);
  3177. CLEANUP:
  3178. return Status;
  3179. }
  3180. PWCHAR *
  3181. ConvertArgv(
  3182. DWORD argc,
  3183. PCHAR *argv
  3184. )
  3185. /*++
  3186. Routine Description:
  3187. Convert short char argv into wide char argv
  3188. Arguments:
  3189. argc - From main
  3190. argv - From main
  3191. Return Value:
  3192. Address of the new argv
  3193. --*/
  3194. {
  3195. PWCHAR *wideargv;
  3196. wideargv = new PWCHAR[argc + 1];
  3197. wideargv[argc] = NULL;
  3198. while (argc-- >= 1) {
  3199. wideargv[argc] = new WCHAR[strlen(argv[argc]) + 1];
  3200. wsprintf(wideargv[argc], L"%hs", argv[argc]);
  3201. }
  3202. return wideargv;
  3203. }
  3204. VOID
  3205. FreeArgv(
  3206. DWORD Argc,
  3207. PWCHAR *Argv
  3208. )
  3209. /*++
  3210. Routine Description:
  3211. Free the converted arguments.
  3212. Arguments:
  3213. Argc - No of arguments.
  3214. Argv - Converted arguments returned from ConvertArgv.
  3215. Return Value:
  3216. None.
  3217. --*/
  3218. {
  3219. while (Argc-- >= 1) {
  3220. FREE(Argv[Argc]);
  3221. }
  3222. FREE(Argv);
  3223. }
  3224. VOID
  3225. Usage(
  3226. PWCHAR *Argv
  3227. )
  3228. /*++
  3229. Routine Description:
  3230. Tell the user how to use the program.
  3231. Arguments:
  3232. Argv Argument array.
  3233. Return Value:
  3234. None
  3235. --*/
  3236. {
  3237. printf("\n");
  3238. printf("%-60s\n", "This tool creates, adds, updates, dumps, and deletes replica set, member, and subscriber objects.\n");
  3239. printf("%-60s%ws /?\n", "Help", Argv[0]);
  3240. printf("%-60s%ws /v\n", "Verbose mode.", Argv[0]);
  3241. printf("%-60s%ws /debug\n", "Debug mode. No Writes to the DC.", Argv[0]);
  3242. printf("%-60s%ws /dc\n", "Name of the DC to connect to.", Argv[0]);
  3243. printf("%-60s%ws /ntfrssettingsdn\n", "Dn for the FRS settings container.", Argv[0]);
  3244. printf("%-60s%ws /setname\n", "Name of the replica set.", Argv[0]);
  3245. printf("%-60s%ws /settype\n", "Type of the replica set.", Argv[0]);
  3246. printf("%-60s\n", "Sysvol = 2");
  3247. printf("%-60s\n", "Dfs = 3");
  3248. printf("%-60s\n\n", "Other = 4");
  3249. printf("%-60s%ws /filefilter\n", "Filter to use against files.e.g. *.bak,*.tmp", Argv[0]);
  3250. printf("%-60s%ws /directoryfilter\n", "Filter to use against directories.", Argv[0]);
  3251. printf("%-60s%ws /primarymember\n", "Name of primary member for initial replica set contents.", Argv[0]);
  3252. printf("%-60s%ws /membername\n", "Name of the member.", Argv[0]);
  3253. printf("%-60s\n", "If DFS naming conventions are desired, specify 'ComputerObjectGuid' for membername.");
  3254. printf("%-60s%ws /dfsname\n", "Name of the dfs in the format <root name>|<junction name>.", Argv[0]);
  3255. printf("%-60s\n", "Required if membername is 'ComputerObjectGuid'.");
  3256. printf("%-60s%ws /computerdn\n", "Dn for the computer object.", Argv[0]);
  3257. printf("%-60s%ws /computername\n", "NT4 style computer name. e.g. NTDEV\\SUDARCTEST$.", Argv[0]);
  3258. printf("%-60s%ws /serverref\n", "Dn of NTDSSettings object for DCs.", Argv[0]);
  3259. printf("%-60s%ws /rootpath\n", "Replica root path. Has to be absolute.", Argv[0]);
  3260. printf("%-60s%ws /stagepath\n", "Replica staging path. Has to be absolute.", Argv[0]);
  3261. printf("%-60s%ws /workingpath\n", "Replica working path. Has to be absolute. Only used if subscriptions obj created.", Argv[0]);
  3262. printf("%-60s%ws /refdcname <dnsname>\n", "Reference DC to use while creating subscriber.", Argv[0]);
  3263. printf("%-60s%ws /[create<object> update<object> del<object> dump]\n", "Operation to be performed.", Argv[0]);
  3264. printf("%-60s%ws \n\n", "<object> can be one of [set member subscriber].", Argv[0]);
  3265. printf("%-60s%ws /all\n", "Perform the operation on all the objects.", Argv[0]);
  3266. printf("%-60s%ws \n\n", "/all only works with /dump and /del.", Argv[0]);
  3267. printf("%-60s%ws /makemeprimary\n", "Make this member object the primary replica set member.", Argv[0]);
  3268. printf("%-60s%ws \n\n", "Applies to member operations only.", Argv[0]);
  3269. printf("%-60s%ws /schedule <Interval> <Stagger> <Offset>\n", "Schedule to create for the replica set.", Argv[0]);
  3270. printf("%-60s%ws <Interval>\n", "The desired interval between each sync with one source.", Argv[0]);
  3271. printf("%-60s%ws <Stagger>\n", "Typically number of source DCs.", Argv[0]);
  3272. printf("%-60s%ws <Offset>\n\n", "Typically the number of the source DC.", Argv[0]);
  3273. printf("%-60s%ws /schedoverride\n", "File with 7x24 vector of schedule override data.", Argv[0]);
  3274. printf("%-60s%ws /schedmask\n", "File with 7x24 vector of schedule mask off data.", Argv[0]);
  3275. printf("%-60s\n", "SchedOverride and SchedMask data are formatted");
  3276. printf("%-60s\n\n", "as 2 ascii hex digits for each schedule byte.");
  3277. DPRINT0("\n");
  3278. DPRINT0("mkdso.exe error return codes\n");
  3279. DPRINT0("100 = Success\n");
  3280. DPRINT0("101 = Invalid Arguments\n");
  3281. DPRINT0("102 = Could not bind to the DC\n");
  3282. DPRINT0("103 = Could not find 'NTFRS Settings' object. Check the /settingsdn parameter\n");
  3283. DPRINT0("104 = Error creating replica set\n");
  3284. DPRINT0("105 = Error updating replica set\n");
  3285. DPRINT0("106 = Error updating replica set; set not found\n");
  3286. DPRINT0("107 = Error updating replica set; duplicate sets found\n");
  3287. DPRINT0("108 = Error deleting replica set; duplicate sets found.\n");
  3288. DPRINT0("109 = Error deleting replica set\n");
  3289. DPRINT0("110 = Error deleting replica set; set not found\n");
  3290. DPRINT0("111 = Deleting multiple sets\n");
  3291. DPRINT0("112 = Error dumping replica set\n");
  3292. DPRINT0("113 = Error dumping replica set; set not found\n");
  3293. DPRINT0("114 = Dumping duplicate sets\n");
  3294. DPRINT0("115 = Error creating replica member\n");
  3295. DPRINT0("116 = Error updating replica member\n");
  3296. DPRINT0("117 = Error updating replica member; member not found\n");
  3297. DPRINT0("118 = Error updating replica member; duplicate members found\n");
  3298. DPRINT0("119 = Error deleting member; duplicate subscribers found.\n");
  3299. DPRINT0("120 = Error deleting replica member\n");
  3300. DPRINT0("121 = Error deleting replica member; member not found\n");
  3301. DPRINT0("122 = Deleting multiple members\n");
  3302. DPRINT0("123 = Error dumping replica member\n");
  3303. DPRINT0("124 = Error dumping replica member; member not found\n");
  3304. DPRINT0("125 = Dumping duplicate members\n");
  3305. DPRINT0("126 = Error creating subscriber\n");
  3306. DPRINT0("127 = Error updating subscriber\n");
  3307. DPRINT0("128 = Error updating subscriber; subscriber not found\n");
  3308. DPRINT0("129 = Error updating subscriber; duplicate subscribers found\n");
  3309. DPRINT0("130 = Error deleting subscriber\n");
  3310. DPRINT0("131 = Error deleting subscriber; subscriber not found\n");
  3311. DPRINT0("132 = Deleting multiple subscribers\n");
  3312. DPRINT0("133 = Error deleting subscriber; duplicate subscribers found.\n");
  3313. DPRINT0("134 = Error dumping subscriber\n");
  3314. DPRINT0("135 = Error dumping subscriber; subscriber not found\n");
  3315. DPRINT0("136 = Dumping duplicate subscribers\n");
  3316. DPRINT0("\n");
  3317. fflush(stdout);
  3318. }
  3319. DWORD __cdecl
  3320. main(
  3321. DWORD argc,
  3322. PCHAR *argv
  3323. )
  3324. /*++
  3325. Routine Description:
  3326. Arguments:
  3327. None.
  3328. Return Value:
  3329. Exits with 0 if everything went okay. Otherwise returns a error code.
  3330. MKDSOE_SUCCESS "Success."
  3331. MKDSOE_BAD_ARG "Invalid Arguments."
  3332. MKDSOE_CANT_BIND "Could not bind to the DC."
  3333. MKDSOE_NO_NTFRS_SETTINGS "Could not find 'NTFRS Settings' object. Check the /settingsdn parameter."
  3334. MKDSOE_SET_OBJ_CRE_FAILED "Error creating replica set."
  3335. MKDSOE_SET_OBJ_UPDATE_FAILED "Error updating replica set."
  3336. MKDSOE_SET_NOT_FOUND_UPDATE "Error updating replica set; set not found."
  3337. MKDSOE_SET_DUPS_FOUND_UPDATE "Error updating replica set; duplicate sets found."
  3338. MKDSOE_SET_DUPS_FOUND_DELETE "Error deleting replica set; duplicate sets found."
  3339. MKDSOE_SET_DELETE_FAILED "Error deleting replica set."
  3340. MKDSOE_SET_NOT_FOUND_DELETE "Error deleting replica set; set not found."
  3341. MKDSOE_MULTIPLE_SETS_DELETED "Deleting multiple sets."
  3342. MKDSOE_SET_DUMP_FAILED "Error dumping replica set."
  3343. MKDSOE_SET_NOT_FOUND_DUMP "Error dumping replica set; set not found."
  3344. MKDSOE_MULTIPLE_SETS_DUMPED "Dumping duplicate sets."
  3345. MKDSOE_MEMBER_OBJ_CRE_FAILED "Error creating replica member."
  3346. MKDSOE_MEMBER_OBJ_UPDATE_FAILED "Error updating replica member."
  3347. MKDSOE_MEMBER_NOT_FOUND_UPDATE "Error updating replica member; member not found."
  3348. MKDSOE_MEMBER_DUPS_FOUND_UPDATE "Error updating replica member; duplicate members found."
  3349. MKDSOE_MEMBER_DUPS_FOUND_DELETE "Error deleting member; duplicate subscribers found."
  3350. MKDSOE_MEMBER_DELETE_FAILED "Error deleting replica member."
  3351. MKDSOE_MEMBER_NOT_FOUND_DELETE "Error deleting replica member; member not found."
  3352. MKDSOE_MULTIPLE_MEMBERS_DELETED "Deleting multiple members."
  3353. MKDSOE_MEMBER_DUMP_FAILED "Error dumping replica member."
  3354. MKDSOE_MEMBER_NOT_FOUND_DUMP "Error dumping replica member; member not found."
  3355. MKDSOE_MULTIPLE_MEMBERS_DUMPED "Dumping duplicate members."
  3356. MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED "Error creating subscriber."
  3357. MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED "Error updating subscriber."
  3358. MKDSOE_SUBSCRIBER_NOT_FOUND_UPDATE "Error updating subscriber; subscriber not found."
  3359. MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE "Error updating subscriber; duplicate subscribers found."
  3360. MKDSOE_SUBSCRIBER_DELETE_FAILED "Error deleting subscriber."
  3361. MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE "Error deleting subscriber; subscriber not found."
  3362. MKDSOE_MULTIPLE_SUBSCRIBERS_DELETED "Deleting multiple subscribers."
  3363. MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE "Error deleting subscriber; duplicate subscribers found."
  3364. MKDSOE_SUBSCRIBER_DUMP_FAILED "Error dumping subscriber."
  3365. MKDSOE_SUBSCRIBER_NOT_FOUND_DUMP "Error dumping subscriber; subscriber not found."
  3366. MKDSOE_MULTIPLE_SUBSCRIBERS_DUMPED "Dumping duplicate subscribers."
  3367. --*/
  3368. {
  3369. PWCHAR *Argv;
  3370. ULONG i, j;
  3371. ULONG OptLen;
  3372. DWORD Status = MKDSOE_SUCCESS;
  3373. DWORD WStatus = ERROR_SUCCESS;
  3374. PWCHAR NTFRSSettingsDn = NULL;
  3375. PWCHAR ReplicaSetName = NULL;
  3376. PWCHAR ReplicaSetType = NULL;
  3377. PWCHAR FileFilter = NULL;
  3378. PWCHAR DirectoryFilter = NULL;
  3379. PWCHAR PrimaryMember = NULL;
  3380. PBYTE pSchedule = NULL;
  3381. DWORD Interval = 1;
  3382. DWORD Stagger = 1;
  3383. DWORD Offset = 0;
  3384. DWORD Vbar;
  3385. PWCHAR NT4ComputerName = NULL;
  3386. PWCHAR ComputerDn = NULL;
  3387. PWCHAR DomainName = NULL;
  3388. PWCHAR MemberName = NULL;
  3389. PWCHAR ServerRef = NULL;
  3390. PWCHAR RootPath = NULL;
  3391. PWCHAR StagePath = NULL;
  3392. PWCHAR WorkingPath = NULL;
  3393. PWCHAR RefDCName = NULL;
  3394. PWCHAR *Values = NULL;
  3395. PWCHAR Switch = NULL;
  3396. PWCHAR pw;
  3397. BOOL ClassFound = FALSE;
  3398. DWORD Commands = 0;
  3399. DS_NAME_RESULT *Cracked = NULL;
  3400. HANDLE hDs = INVALID_HANDLE_VALUE;
  3401. PLDAP_BERVAL *BerValues = NULL;
  3402. GUID *Guid = NULL;
  3403. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  3404. BOOL bRetry = FALSE;
  3405. DWORD DcFlags;
  3406. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pBuffer = NULL;
  3407. Argv = ConvertArgv(argc, argv);
  3408. if (argc <= 1) {
  3409. Usage(Argv);
  3410. Status = MKDSOE_SUCCESS;
  3411. goto ARG_CLEANUP;
  3412. }
  3413. for (i = 1; i < argc; ++i) {
  3414. OptLen = wcslen(Argv[i]);
  3415. _wcslwr(Argv[i]);
  3416. Switch = Argv[i];
  3417. DPRINT1(" %20ws ", Switch);
  3418. if ((*Switch != L'/') && (*Switch != L'-')) {
  3419. Usage(Argv);
  3420. Status = MKDSOE_BAD_ARG;
  3421. goto ARG_CLEANUP;
  3422. }
  3423. ++Switch; // jump over -
  3424. if (OptLen == 2 && ArgMatch(Switch, L"v")) {
  3425. bVerboseMode=TRUE;
  3426. DPRINT1(" %20ws ", Switch);
  3427. } else if (OptLen == 3 && ArgMatch(Switch, L"vs")) {
  3428. bVerboseModeSearch=TRUE;
  3429. DPRINT1(" %20ws ", Switch);
  3430. } else if (OptLen == 2 && ArgMatch(Switch, L"?")) {
  3431. Usage(Argv);
  3432. Status = MKDSOE_SUCCESS;
  3433. goto ARG_CLEANUP;
  3434. } else if (OptLen == 6 && ArgMatch(Switch, L"debug")) {
  3435. bDebugMode = TRUE;
  3436. bVerboseMode=TRUE;
  3437. } else if (OptLen == 3 && (i+1 < argc) && ArgMatch(Switch, L"dc")) {
  3438. i += 1;
  3439. DcName = new WCHAR[wcslen(Argv[i])+1];
  3440. wcscpy(DcName, Argv[i]);
  3441. DPRINT1("%ws", DcName);
  3442. } else if (OptLen == 16 && (i+1 < argc) && ArgMatch(Switch, L"ntfrssettingsdn")) {
  3443. i += 1;
  3444. NTFRSSettingsDn = new WCHAR[wcslen(Argv[i])+1];
  3445. wcscpy(NTFRSSettingsDn, Argv[i]);
  3446. DPRINT1("%ws", NTFRSSettingsDn);
  3447. } else if (OptLen == 8 && (i+1 < argc) && ArgMatch(Switch, L"setname")) {
  3448. i += 1;
  3449. ReplicaSetName = new WCHAR[wcslen(Argv[i])+1];
  3450. wcscpy(ReplicaSetName, Argv[i]);
  3451. DPRINT1("%ws", ReplicaSetName);
  3452. } else if (OptLen == 11 && (i+1 < argc) && ArgMatch(Switch, L"computerdn")) {
  3453. i += 1;
  3454. ComputerDn = new WCHAR[wcslen(Argv[i])+1];
  3455. wcscpy(ComputerDn, Argv[i]);
  3456. DPRINT1("%ws", ComputerDn);
  3457. } else if (OptLen == 13 && (i+1 < argc) && ArgMatch(Switch, L"computername")) {
  3458. i += 1;
  3459. NT4ComputerName = new WCHAR[wcslen(Argv[i])+1];
  3460. wcscpy(NT4ComputerName, Argv[i]);
  3461. DPRINT1("%ws", NT4ComputerName);
  3462. } else if (OptLen == 11 && (i+1 < argc) && ArgMatch(Switch, L"membername")) {
  3463. i += 1;
  3464. MemberName = new WCHAR[wcslen(Argv[i])+1];
  3465. wcscpy(MemberName, Argv[i]);
  3466. DPRINT1("%ws", MemberName);
  3467. } else if (OptLen == 11 && (i+1 < argc) && ArgMatch(Switch, L"membername")) {
  3468. i += 1;
  3469. MemberName = new WCHAR[wcslen(Argv[i])+1];
  3470. wcscpy(MemberName, Argv[i]);
  3471. DPRINT1("%ws", MemberName);
  3472. } else if (OptLen == 8 && (i+1 < argc) && ArgMatch(Switch, L"dfsname")) {
  3473. i += 1;
  3474. DFSName = new WCHAR[wcslen(Argv[i])+1];
  3475. wcscpy(DFSName, Argv[i]);
  3476. DPRINT1("%ws", DFSName);
  3477. bDFSNaming = TRUE;
  3478. } else if (OptLen == 9 && (i+1 < argc) && ArgMatch(Switch, L"rootpath")) {
  3479. i += 1;
  3480. RootPath = new WCHAR[wcslen(Argv[i])+1];
  3481. wcscpy(RootPath, Argv[i]);
  3482. DPRINT1("%ws", RootPath);
  3483. } else if (OptLen == 10 && (i+1 < argc) && ArgMatch(Switch, L"stagepath")) {
  3484. i += 1;
  3485. StagePath = new WCHAR[wcslen(Argv[i])+1];
  3486. wcscpy(StagePath, Argv[i]);
  3487. DPRINT1("%ws", StagePath);
  3488. } else if (OptLen == 12 && (i+1 < argc) && ArgMatch(Switch, L"workingpath")) {
  3489. i += 1;
  3490. WorkingPath = new WCHAR[wcslen(Argv[i])+1];
  3491. wcscpy(WorkingPath, Argv[i]);
  3492. DPRINT1("%ws", WorkingPath);
  3493. } else if (OptLen == 10 && (i+1 < argc) && ArgMatch(Switch, L"refdcname")) {
  3494. i += 1;
  3495. RefDCName = new WCHAR[wcslen(Argv[i])+1];
  3496. wcscpy(RefDCName, Argv[i]);
  3497. DPRINT1("%ws", RefDCName);
  3498. } else if (OptLen == 10 && ArgMatch(Switch, L"createset")) {
  3499. bCreateSet = TRUE;
  3500. ++Commands;
  3501. } else if (OptLen == 10 && ArgMatch(Switch, L"updateset")) {
  3502. bUpdateSet = TRUE;
  3503. ++Commands;
  3504. } else if (OptLen == 7 && ArgMatch(Switch, L"delset")) {
  3505. bDelSet = TRUE;
  3506. ++Commands;
  3507. } else if (OptLen == 13 && ArgMatch(Switch, L"createmember")) {
  3508. bCreateMember = TRUE;
  3509. ++Commands;
  3510. } else if (OptLen == 13 && ArgMatch(Switch, L"updatemember")) {
  3511. bUpdateMember = TRUE;
  3512. ++Commands;
  3513. } else if (OptLen == 10 && ArgMatch(Switch, L"delmember")) {
  3514. bDelMember = TRUE;
  3515. ++Commands;
  3516. } else if (OptLen == 17 && ArgMatch(Switch, L"createsubscriber")) {
  3517. bCreateSubscriber = TRUE;
  3518. ++Commands;
  3519. } else if (OptLen == 17 && ArgMatch(Switch, L"updatesubscriber")) {
  3520. bUpdateSubscriber = TRUE;
  3521. ++Commands;
  3522. } else if (OptLen == 14 && ArgMatch(Switch, L"delsubscriber")) {
  3523. bDelSubscriber = TRUE;
  3524. ++Commands;
  3525. } else if (OptLen == 5 && ArgMatch(Switch, L"dump")) {
  3526. bDump = TRUE;
  3527. ++Commands;
  3528. } else if (OptLen == 4 && ArgMatch(Switch, L"all")) {
  3529. bAffectAll = TRUE;
  3530. } else if (OptLen == 8 && (i+1 < argc) && ArgMatch(Switch, L"settype")) {
  3531. i += 1;
  3532. ReplicaSetType = new WCHAR[wcslen(Argv[i])+1];
  3533. wcscpy(ReplicaSetType, Argv[i]);
  3534. DPRINT1("%ws", ReplicaSetType);
  3535. } else if (OptLen == 11 && (i+1 < argc) && ArgMatch(Switch, L"filefilter")) {
  3536. i += 1;
  3537. FileFilter = new WCHAR[wcslen(Argv[i])+1];
  3538. wcscpy(FileFilter, Argv[i]);
  3539. DPRINT1("%ws", FileFilter);
  3540. } else if (OptLen == 16 && (i+1 < argc) && ArgMatch(Switch, L"directoryfilter")) {
  3541. i += 1;
  3542. DirectoryFilter = new WCHAR[wcslen(Argv[i])+1];
  3543. wcscpy(DirectoryFilter, Argv[i]);
  3544. DPRINT1("%ws", DirectoryFilter);
  3545. } else if (OptLen == 14 && (i+1 < argc) && ArgMatch(Switch, L"primarymember")) {
  3546. i += 1;
  3547. PrimaryMember = new WCHAR[wcslen(Argv[i])+1];
  3548. wcscpy(PrimaryMember, Argv[i]);
  3549. DPRINT1("%ws", PrimaryMember);
  3550. } else if (OptLen == 14 && ArgMatch(Switch, L"makemeprimary")) {
  3551. bMakeMePrimary = TRUE;
  3552. } else if (OptLen == 9 && (i+3 < argc) && ArgMatch(Switch, L"schedule")) {
  3553. bSchedule = TRUE;
  3554. Interval = _wtoi(Argv[i+1]);
  3555. Stagger = _wtoi(Argv[i+2]);
  3556. Offset = _wtoi(Argv[i+3]);
  3557. i+=3;
  3558. } else if ((OptLen == 10) && (i+1 < argc) && ArgMatch(Switch, L"schedmask")) {
  3559. SchedMask = ReadScheduleFile(Argv[i+1]);
  3560. if (SchedMask == NULL) {
  3561. FreeArgv(argc,Argv);
  3562. return MKDSOE_BAD_ARG;
  3563. } else {
  3564. if (bVerboseMode) {
  3565. printf(" schedmask:\n");
  3566. PrintScheduleGrid(SchedMask, 0x0F);
  3567. }
  3568. }
  3569. i+=1;
  3570. } else if ((OptLen == 14) && (i+1 < argc) && ArgMatch(Switch, L"schedoverride")) {
  3571. SchedOverride = ReadScheduleFile(Argv[i+1]);
  3572. if (SchedOverride == NULL) {
  3573. FreeArgv(argc,Argv);
  3574. return MKDSOE_BAD_ARG;
  3575. } else {
  3576. if (bVerboseMode) {
  3577. printf(" schedoverride:\n");
  3578. PrintScheduleGrid(SchedOverride, 0x0F);
  3579. }
  3580. }
  3581. i+=1;
  3582. } else {
  3583. Usage(Argv);
  3584. Status = MKDSOE_BAD_ARG;
  3585. goto ARG_CLEANUP;
  3586. }
  3587. DPRINT0("\n");
  3588. }
  3589. //
  3590. // Begin of verify command line parameters.
  3591. //
  3592. if (Commands != 1) {
  3593. if ((Commands == 2) && bDelSubscriber &&bDelMember) {
  3594. //
  3595. // The only time two commands are allowed is when /delsubscriber
  3596. // is used with /delmember
  3597. //
  3598. } else {
  3599. DPRINT0("INVALID ARG: Specify one and only one command except /delmember /delsubscriber.\n");
  3600. Status = MKDSOE_BAD_ARG;
  3601. goto ARG_CLEANUP;
  3602. }
  3603. }
  3604. if (NTFRSSettingsDn == NULL) {
  3605. DPRINT0("INVALID ARG: Missing parameter /ntfrssettingsdn.\n");
  3606. Status = MKDSOE_BAD_ARG;
  3607. goto ARG_CLEANUP;
  3608. }
  3609. if ((ReplicaSetName == NULL) && !(bDump && bAffectAll)) {
  3610. DPRINT0("INVALID ARG: Missing parameter /setname.\n");
  3611. Status = MKDSOE_BAD_ARG;
  3612. goto ARG_CLEANUP;
  3613. }
  3614. if (bCreateSet && ReplicaSetType == NULL) {
  3615. DPRINT0("INVALID ARG: Missing parameter /settype.\n");
  3616. Status = MKDSOE_BAD_ARG;
  3617. goto ARG_CLEANUP;
  3618. }
  3619. if (bCreateMember) {
  3620. if (MemberName == NULL) {
  3621. DPRINT0("INVALID ARG: Missing parameter /membername.\n");
  3622. Status = MKDSOE_BAD_ARG;
  3623. goto ARG_CLEANUP;
  3624. }
  3625. if (bDFSNaming) {
  3626. if (DFSName == NULL) {
  3627. DPRINT0("INVALID ARG: Missing parameter /dfsname.\n");
  3628. Status = MKDSOE_BAD_ARG;
  3629. goto ARG_CLEANUP;
  3630. }
  3631. Vbar = wcscspn(DFSName, L"|");
  3632. if ((Vbar == wcslen(DFSName)) ||
  3633. (Vbar == 0) ||
  3634. ((wcslen(DFSName) - Vbar) < 2)) {
  3635. //
  3636. // No vertical bar found or root or junction parts are zero len.
  3637. //
  3638. DPRINT0("INVALID ARG: Member name must have v-bar with root and junction parts for DFS naming. /dfsname.\n");
  3639. Status = MKDSOE_BAD_ARG;
  3640. goto ARG_CLEANUP;
  3641. }
  3642. }
  3643. }
  3644. if (bMakeMePrimary && (bCreateSet || bUpdateSet || bDelSet || bDelMember)) {
  3645. DPRINT0("INVALID ARG: /makemeprimary not allowed with /createset, /updateset, /delset, or /delmember.\n");
  3646. Status = MKDSOE_BAD_ARG;
  3647. goto ARG_CLEANUP;
  3648. }
  3649. if (bUpdateMember) {
  3650. if ((MemberName == NULL) &&
  3651. (ComputerDn == NULL) &&
  3652. (NT4ComputerName == NULL)) {
  3653. DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
  3654. Status = MKDSOE_BAD_ARG;
  3655. goto ARG_CLEANUP;
  3656. }
  3657. }
  3658. if (bCreateSubscriber) {
  3659. if ((MemberName == NULL) &&
  3660. (ComputerDn == NULL) &&
  3661. (NT4ComputerName == NULL)) {
  3662. DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
  3663. Status = MKDSOE_BAD_ARG;
  3664. goto ARG_CLEANUP;
  3665. }
  3666. if (RootPath == NULL) {
  3667. DPRINT0("INVALID ARG: Missing parameter /rootpath.\n");
  3668. Status = MKDSOE_BAD_ARG;
  3669. goto ARG_CLEANUP;
  3670. }
  3671. if (StagePath == NULL) {
  3672. DPRINT0("INVALID ARG: Missing parameter /stagepath.\n");
  3673. Status = MKDSOE_BAD_ARG;
  3674. goto ARG_CLEANUP;
  3675. }
  3676. if (bDFSNaming) {
  3677. if (DFSName == NULL) {
  3678. DPRINT0("INVALID ARG: Missing parameter /dfsname.\n");
  3679. Status = MKDSOE_BAD_ARG;
  3680. goto ARG_CLEANUP;
  3681. }
  3682. Vbar = wcscspn(DFSName, L"|");
  3683. if ((Vbar == wcslen(DFSName)) ||
  3684. (Vbar == 0) ||
  3685. ((wcslen(DFSName) - Vbar) < 2)) {
  3686. //
  3687. // No vertical bar found or root or junction parts are zero len.
  3688. //
  3689. DPRINT0("INVALID ARG: Member name must have v-bar with root and junction parts for DFS naming. /dfsname.\n");
  3690. Status = MKDSOE_BAD_ARG;
  3691. goto ARG_CLEANUP;
  3692. }
  3693. }
  3694. }
  3695. if (bUpdateSubscriber) {
  3696. if ((MemberName == NULL) &&
  3697. (ComputerDn == NULL) &&
  3698. (NT4ComputerName == NULL)) {
  3699. DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
  3700. Status = MKDSOE_BAD_ARG;
  3701. goto ARG_CLEANUP;
  3702. }
  3703. }
  3704. if (bDelMember) {
  3705. if (!bAffectAll &&
  3706. (MemberName == NULL) &&
  3707. (ComputerDn == NULL) &&
  3708. (NT4ComputerName == NULL)) {
  3709. DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername or /all.\n");
  3710. Status = MKDSOE_BAD_ARG;
  3711. goto ARG_CLEANUP;
  3712. }
  3713. }
  3714. if (bDelSubscriber) {
  3715. if (!bDelMember &&
  3716. (MemberName == NULL) &&
  3717. (ComputerDn == NULL) &&
  3718. (NT4ComputerName == NULL)) {
  3719. DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
  3720. Status = MKDSOE_BAD_ARG;
  3721. goto ARG_CLEANUP;
  3722. }
  3723. }
  3724. //
  3725. // End of verify command line parameters.
  3726. //
  3727. Status = BindToDC(DcName, &pLdap);
  3728. //
  3729. // Verify that the ntfrs settings DN exists and is actually a NTFRSSettings object.
  3730. //
  3731. i=0;
  3732. ClassFound = FALSE;
  3733. Values = GetValues(pLdap, NTFRSSettingsDn, ATTR_CLASS, TRUE);
  3734. while (Values && Values[i]) {
  3735. if (_wcsicmp(Values[i],ATTR_NTFRS_SETTINGS) == 0) {
  3736. ClassFound = TRUE;
  3737. break;
  3738. }
  3739. ++i;
  3740. }
  3741. LDAP_FREE_VALUES(Values);
  3742. if (!ClassFound) {
  3743. DPRINT0("INVALID ARG: Check parameter /ntfrssettingsdn.\n");
  3744. Status = MKDSOE_NO_NTFRS_SETTINGS;
  3745. goto CLEANUP;
  3746. }
  3747. //
  3748. // Verify that the computer DN exists and is actually a computer object.
  3749. //
  3750. if (ComputerDn != NULL) {
  3751. i=0;
  3752. ClassFound = FALSE;
  3753. Values = GetValues(pLdap, ComputerDn, ATTR_CLASS, TRUE);
  3754. while (Values && Values[i]) {
  3755. if ((_wcsicmp(Values[i],ATTR_COMPUTER)== 0) ||
  3756. (_wcsicmp(Values[i],ATTR_USER) == 0)) {
  3757. ClassFound = TRUE;
  3758. break;
  3759. }
  3760. ++i;
  3761. }
  3762. LDAP_FREE_VALUES(Values);
  3763. if (!ClassFound) {
  3764. DPRINT0("INVALID ARG: Check parameter /computerdn.\n");
  3765. Status = MKDSOE_BAD_ARG;
  3766. goto CLEANUP;
  3767. }
  3768. }
  3769. if (bCreateSet) {
  3770. if (bSchedule) {
  3771. BuildSchedule(&pSchedule, Interval, Stagger, Offset);
  3772. Status = CreateNewReplicaSet(NTFRSSettingsDn,ReplicaSetName,
  3773. ReplicaSetType, FileFilter,
  3774. DirectoryFilter, PrimaryMember, pSchedule);
  3775. } else {
  3776. Status = CreateNewReplicaSet(NTFRSSettingsDn,ReplicaSetName,
  3777. ReplicaSetType, FileFilter,
  3778. DirectoryFilter, PrimaryMember, NULL);
  3779. }
  3780. }
  3781. if (bUpdateSet) {
  3782. if (bSchedule) {
  3783. BuildSchedule(&pSchedule, Interval, Stagger, Offset);
  3784. Status = UpdateReplicaSet(NTFRSSettingsDn,ReplicaSetName,
  3785. ReplicaSetType, FileFilter,
  3786. DirectoryFilter, PrimaryMember, pSchedule);
  3787. } else {
  3788. Status = UpdateReplicaSet(NTFRSSettingsDn,ReplicaSetName,
  3789. ReplicaSetType, FileFilter,
  3790. DirectoryFilter, PrimaryMember, NULL);
  3791. }
  3792. }
  3793. if (bCreateMember || bUpdateMember || bCreateSubscriber || bUpdateSubscriber ||
  3794. bDelSubscriber || bDelMember) {
  3795. //
  3796. // Get the Coumputer Dn using the NT4 account name.
  3797. //
  3798. if ((ComputerDn == NULL) && (NT4ComputerName != NULL)) {
  3799. if (hDs == INVALID_HANDLE_VALUE) {
  3800. WStatus = DsBind(DcName, NULL, &hDs);
  3801. if (WStatus != ERROR_SUCCESS) {
  3802. DPRINT2("ERROR: Can not bind to DC (%ws) %d\n", DcName, WStatus);
  3803. Status = MKDSOE_BAD_ARG;
  3804. goto CLEANUP;
  3805. }
  3806. }
  3807. WStatus = DsCrackNames(hDs, // in hDS,
  3808. DS_NAME_NO_FLAGS, // in flags,
  3809. DS_NT4_ACCOUNT_NAME, // in formatOffered,
  3810. DS_FQDN_1779_NAME, // in formatDesired,
  3811. 1, // in cNames,
  3812. &NT4ComputerName, // in *rpNames,
  3813. &Cracked); // out *ppResult
  3814. if ((WStatus == ERROR_SUCCESS) &&
  3815. Cracked && Cracked->cItems && Cracked->rItems &&
  3816. (Cracked->rItems->status == DS_NAME_NO_ERROR)) {
  3817. ComputerDn = FrsWcsDup(Cracked->rItems->pName);
  3818. DsFreeNameResult(Cracked);
  3819. } else {
  3820. DPRINT1("ERROR: Can not crack computerDn %d\n", WStatus);
  3821. Status = MKDSOE_BAD_ARG;
  3822. goto CLEANUP;
  3823. }
  3824. }
  3825. //
  3826. bugbug ("we need the domain guid for the DFSRoot's Domain NC which may not be the same as the member")
  3827. // Get the domain GUID for the domain containing the member.
  3828. //
  3829. if ((ComputerDn != NULL) && bCreateSubscriber) {
  3830. if (hDs == INVALID_HANDLE_VALUE) {
  3831. WStatus = DsBind(DcName, NULL, &hDs);
  3832. if (WStatus != ERROR_SUCCESS) {
  3833. DPRINT2("ERROR: Can not bind to DC (%ws) %d\n", DcName, WStatus);
  3834. Status = MKDSOE_BAD_ARG;
  3835. goto CLEANUP;
  3836. }
  3837. }
  3838. //
  3839. // First get the DS_CANONICAL_NAME.
  3840. // eg: engineering.widget.com/software/spencer katt
  3841. // Domain-only version includes trailing '/'.
  3842. //
  3843. WStatus = DsCrackNames(hDs, // in hDS,
  3844. DS_NAME_NO_FLAGS, // in flags,
  3845. DS_FQDN_1779_NAME, // in formatOffered,
  3846. DS_CANONICAL_NAME, // in formatDesired,
  3847. 1, // in cNames,
  3848. &ComputerDn, // in *rpNames,
  3849. &Cracked); // out *ppResult
  3850. if ((WStatus == ERROR_SUCCESS) &&
  3851. Cracked && Cracked->cItems && Cracked->rItems &&
  3852. (Cracked->rItems->status == DS_NAME_NO_ERROR)) {
  3853. //
  3854. // Get the Canonical name and terminate the string after the domain name.
  3855. //
  3856. DomainName = FrsWcsDup(Cracked->rItems->pName);
  3857. DPRINT1("Canonical name: %ws\n", DomainName);
  3858. pw = DomainName;
  3859. while (*pw && (*pw != L'\\')) {
  3860. pw++;
  3861. }
  3862. if (pw != DomainName) {
  3863. *pw = L'\0';
  3864. }
  3865. DPRINT1("Domain name: %ws\n", DomainName);
  3866. DsFreeNameResult(Cracked);
  3867. } else {
  3868. DPRINT2("ERROR: Can not crack canonical name (%ws) %d\n", ComputerDn, WStatus);
  3869. Status = MKDSOE_BAD_ARG;
  3870. goto CLEANUP;
  3871. }
  3872. //
  3873. // Take the domain name and get the domain GUID.
  3874. //
  3875. WStatus = DsCrackNames(hDs, // in hDS,
  3876. DS_NAME_NO_FLAGS, // in flags,
  3877. DS_CANONICAL_NAME, // in formatOffered,
  3878. DS_UNIQUE_ID_NAME, // in formatDesired,
  3879. 1, // in cNames,
  3880. &DomainName, // in *rpNames,
  3881. &Cracked); // out *ppResult
  3882. if ((WStatus == ERROR_SUCCESS) &&
  3883. Cracked && Cracked->cItems && Cracked->rItems &&
  3884. (Cracked->rItems->status == DS_NAME_NO_ERROR)) {
  3885. DomainGuidStr = FrsWcsDup(Cracked->rItems->pName);
  3886. DPRINT1("Canonical name: %ws\n", DomainGuidStr);
  3887. DsFreeNameResult(Cracked);
  3888. } else {
  3889. DPRINT2("ERROR: Can not crack canonical DomainName (%ws) %d\n", DomainName, WStatus);
  3890. Status = MKDSOE_BAD_ARG;
  3891. goto CLEANUP;
  3892. }
  3893. #if 0
  3894. // Alternate sequence if above fails.
  3895. DcFlags = DS_DIRECTORY_SERVICE_PREFERRED;
  3896. do {
  3897. //
  3898. // Get a DC name for a DC in the domain containing this member.
  3899. //
  3900. WStatus = DsGetDcName(NULL, DomainName, NULL, NULL, DcFlags, &pDCInfo);
  3901. if (WStatus != ERROR_SUCCESS) {
  3902. DPRINT1("ERROR: Can not get computer name of DC in member's domain. (%ws)\n", DomainName);
  3903. Status = MKDSOE_BAD_ARG;
  3904. NetApiBufferFree(pDCInfo);
  3905. goto CLEANUP;
  3906. }
  3907. if ( !(pDCInfo->Flags & DS_DS_FLAG) ) {
  3908. // down level domain
  3909. DPRINT1("ERROR: ComputerDn in down level domains not supported. (%ws)\n", DomainName);
  3910. Status = MKDSOE_BAD_ARG;
  3911. NetApiBufferFree(pDCInfo);
  3912. goto CLEANUP;
  3913. }
  3914. //
  3915. // Get the domain guid.
  3916. //
  3917. WStatus = DsRoleGetPrimaryDomainInformation(pDCInfo->DomainControllerName,
  3918. DsRolePrimaryDomainInfoBasic,
  3919. (PBYTE *)&pBuffer);
  3920. if ((WStatus == RPC_S_SERVER_UNAVAILABLE) && !bRetry) {
  3921. bRetry = TRUE; // only retry once
  3922. NetApiBufferFree(pDCInfo);
  3923. DcFlags |= DS_FORCE_REDISCOVERY;
  3924. } else {
  3925. break;
  3926. }
  3927. } while (1);
  3928. if (WStatus == ERROR_SUCCESS) {
  3929. Guid = &pBuffer->DomainGuid;
  3930. //
  3931. // Build stringized Guid in the format returned by the DS.
  3932. // It has an extra dash.
  3933. // e.g. DsCrackNames(hDs,DS_NAME_NO_FLAGS, DS_NT4_ACCOUNT_NAME,
  3934. // DS_UNIQUE_ID_NAME, 1, &NT4ComputerName, &Cracked);
  3935. //
  3936. swprintf(DomainGuidStr,
  3937. L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  3938. Guid->Data1, Guid->Data2, Guid->Data3,
  3939. Guid->Data4[0], Guid->Data4[1], Guid->Data4[2], Guid->Data4[3],
  3940. Guid->Data4[4], Guid->Data4[5], Guid->Data4[6], Guid->Data4[7]);
  3941. Guid = NULL;
  3942. DsRoleFreeMemory(pBuffer);
  3943. NetApiBufferFree(pDCInfo);
  3944. } else {
  3945. DPRINT1("ERROR: Failed to get domain GUID for computer (%ws)\n", ComputerDn);
  3946. Status = MKDSOE_BAD_ARG;
  3947. NetApiBufferFree(pDCInfo);
  3948. goto CLEANUP;
  3949. }
  3950. }
  3951. #endif
  3952. if (hDs != INVALID_HANDLE_VALUE) {
  3953. DsUnBind(&hDs);
  3954. }
  3955. //
  3956. // Go get the Guid of the computer object and convert to stringized form
  3957. // that the FRS GUI Snapin will recognize.
  3958. //
  3959. BerValues = GetBerValues(pLdap, ComputerDn, ATTR_OBJECT_GUID, TRUE);
  3960. if (BerValues && BerValues[0]) {
  3961. // Copy the first value (if any)
  3962. Guid = (GUID *)BerValues[0]->bv_val;
  3963. }
  3964. if (Guid != NULL) {
  3965. //
  3966. // Build stringized Guid in the format returned by the DS.
  3967. // It has an extra dash.
  3968. // e.g. DsCrackNames(hDs,DS_NAME_NO_FLAGS, DS_NT4_ACCOUNT_NAME,
  3969. // DS_UNIQUE_ID_NAME, 1, &NT4ComputerName, &Cracked);
  3970. //
  3971. swprintf(ComputerObjectGuidStr,
  3972. L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  3973. Guid->Data1, Guid->Data2, Guid->Data3,
  3974. Guid->Data4[0], Guid->Data4[1], Guid->Data4[2], Guid->Data4[3],
  3975. Guid->Data4[4], Guid->Data4[5], Guid->Data4[6], Guid->Data4[7]);
  3976. Guid = NULL;
  3977. } else {
  3978. DPRINT1("INVALID ARG: Cannot get Object Guid for computerdn (%ws).\n", ComputerDn);
  3979. Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
  3980. goto CLEANUP;
  3981. }
  3982. // Free ldap's array of BerValues
  3983. LDAP_FREE_BER_VALUES(BerValues);
  3984. //
  3985. // Check if MemberName is "ComputerObjectGuid". If so then use the
  3986. // stringized Guid to make the FRS UI (in the DFS UI) happy.
  3987. // Else use the MemberName itself.
  3988. //
  3989. if (ArgMatch(MemberName, L"ComputerObjectGuid")) {
  3990. FREE(MemberName);
  3991. MemberName = new WCHAR[wcslen(ComputerObjectGuidStr)+1];
  3992. wcscpy(MemberName, ComputerObjectGuidStr);
  3993. DPRINT1("Member name conversion to GUID: %ws\n", MemberName);
  3994. bDFSNaming = TRUE;
  3995. }
  3996. if (bCreateMember) {
  3997. Status = CreateNewReplicaMember(NTFRSSettingsDn, ReplicaSetName,
  3998. MemberName, ComputerDn, ServerRef,
  3999. RefDCName);
  4000. }
  4001. if (bUpdateMember) {
  4002. Status = UpdateReplicaMember(NTFRSSettingsDn, ReplicaSetName,
  4003. MemberName, ComputerDn, ServerRef,
  4004. RefDCName);
  4005. }
  4006. if (bDelMember) {
  4007. Status = DeleteReplicaMember(NTFRSSettingsDn, ReplicaSetName,
  4008. MemberName,ComputerDn);
  4009. }
  4010. if (bCreateSubscriber || bUpdateSubscriber) {
  4011. Status = CreateNewSubscriber(NTFRSSettingsDn, ReplicaSetName,
  4012. MemberName, ComputerDn,
  4013. RootPath, StagePath, WorkingPath, RefDCName);
  4014. }
  4015. if (bDelSubscriber && !bDelMember) {
  4016. Status = DeleteSubscriber(NTFRSSettingsDn, ReplicaSetName,
  4017. MemberName, ComputerDn);
  4018. }
  4019. }
  4020. if (bDelSet) {
  4021. Status = DeleteReplicaSet(NTFRSSettingsDn, ReplicaSetName);
  4022. }
  4023. if (bDump ) {
  4024. DumpReplicaSet(NTFRSSettingsDn, ReplicaSetName);
  4025. }
  4026. goto CLEANUP;
  4027. CLEANUP:
  4028. ldap_unbind(pLdap);
  4029. ARG_CLEANUP:
  4030. FreeArgv(argc,Argv);
  4031. FREE(MemberName);
  4032. FREE(ReplicaSetName);
  4033. FREE(ComputerDn);
  4034. FREE(NT4ComputerName);
  4035. return Status;
  4036. }