Source code of Windows XP (NT5)
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.

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