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.

7939 lines
239 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. api.c
  5. Abstract:
  6. Application Programmer's Interface
  7. The dcpromo APIs are used when promoting or demoting a machine. The
  8. APIs seed the sysvols after promotion. The sysvols are deleted
  9. during demotion.
  10. The poke API forces the service on the indicated machine to
  11. immediately poll the DS.
  12. Author:
  13. Billy J. Fuller 31-Dec-1997
  14. Environment
  15. User mode winnt
  16. --*/
  17. #include <ntreppch.h>
  18. #pragma hdrstop
  19. #include <frs.h>
  20. #include <ntfrsapi.h>
  21. #include <lmaccess.h>
  22. #include <lmapibuf.h>
  23. #include <frssup.h>
  24. CRITICAL_SECTION NtFrsApi_GlobalLock;
  25. CRITICAL_SECTION NtFrsApi_ThreadLock;
  26. DWORD NtFrsApi_State;
  27. DWORD NtFrsApi_ServiceState;
  28. DWORD NtFrsApi_ServiceWaitHint;
  29. HANDLE NtFrsApi_ShutDownEvent;
  30. PWCHAR NtFrsApi_ServiceLongName = SERVICE_LONG_NAME;
  31. //
  32. // API Version Information
  33. //
  34. PCHAR NtFrsApi_Module = __FILE__;
  35. PCHAR NtFrsApi_Date = __DATE__;
  36. PCHAR NtFrsApi_Time = __TIME__;
  37. // Seed the sysvol after dcpromo
  38. // Update the registry, delete existing sysvols (w/o error),
  39. // set service to auto-start
  40. //
  41. //
  42. // NTFRSAPI States
  43. //
  44. #define NTFRSAPI_LOADED (00)
  45. #define NTFRSAPI_PREPARING (10)
  46. #define NTFRSAPI_PREPARED_SERVICE (15)
  47. #define NTFRSAPI_PREPARED (20)
  48. #define NTFRSAPI_COMMITTING (30)
  49. #define NTFRSAPI_COMMITTED (40)
  50. #define NTFRSAPI_ABORTING (50)
  51. #define NTFRSAPI_ABORTED (60)
  52. //
  53. // Useful macros
  54. //
  55. #undef GET_EXCEPTION_CODE
  56. #define GET_EXCEPTION_CODE(_x_) \
  57. { \
  58. (_x_) = GetExceptionCode(); \
  59. if (((LONG)(_x_)) < 0) { \
  60. (_x_) = FRS_ERR_INTERNAL_API; \
  61. } \
  62. NTFRSAPI_DBG_PRINT2("Exception caught: %d, 0x%08x\n", (_x_), (_x_)); \
  63. }
  64. #define FREE(_x_) { if (_x_) { LocalFree(_x_); (_x_) = NULL; } }
  65. //
  66. // Status Polling Interval
  67. //
  68. #define STATUS_POLLING_INTERVAL (1 * 1000) // 1 second
  69. //
  70. // Ldap timeout
  71. //
  72. #define NTFRSAPI_LDAP_CONNECT_TIMEOUT 30 // 30 seconds.
  73. //
  74. // DEBUG LOGGING
  75. //
  76. #define NTFRSAPI_DBG_LOG_DIR L"%SystemRoot%\\debug"
  77. #define NTFRSAPI_DBG_LOG_FILE L"\\NtFrsApi.log"
  78. WCHAR NtFrsApi_Dbg_LogFile[MAX_PATH + 1];
  79. FILE *NtFrsApi_Dbg_LogFILE;
  80. CRITICAL_SECTION NtFrsApi_Dbg_Lock;
  81. //
  82. // Semaphore name used to serialize backup restore operations.
  83. //
  84. #define NTFRS_BACKUP_RESTORE_SEMAPHORE L"NtFrs Backup Restore Semaphore"
  85. #define CLEANUP_CB(_cb_func, _str, _wstatus, _branch) \
  86. if (!WIN_SUCCESS(_wstatus)) { \
  87. NtFrsApi_CallBackOnWStatus((_cb_func), (_str), _wstatus); \
  88. goto _branch; \
  89. }
  90. #define MAX_DN (8 * MAX_PATH)
  91. WCHAR DsDeleteDefaultDn[MAX_PATH + 1];
  92. WCHAR DsDeleteConfigDn[MAX_PATH + 1];
  93. WCHAR DsDeleteComputerName[MAX_COMPUTERNAME_LENGTH + 2];
  94. WCHAR DsDeleteDomainDnsName[MAX_PATH + 2];
  95. PLDAP DsDeleteLdap;
  96. //
  97. // Name components for FQDN substitution. Used to build a string substitution
  98. // array that is driven by a table to build the desired FQDN.
  99. //
  100. typedef enum _FQDN_ARG_STRING {
  101. FQDN_END = 0, // Null
  102. FQDN_ComputerName, // DsDeleteComputerName,
  103. FQDN_ConfigName, // DsDeleteConfigDn,
  104. FQDN_RepSetName, // Thread->ReplicaSetName,
  105. FQDN_DefaultDn, // DsDeleteDefaultDn,
  106. FQDN_CN_SYSVOLS, // CN_SYSVOLS,
  107. FQDN_CN_SERVICES, // CN_SERVICES
  108. FQDN_CN_DOMAIN_SYSVOL, // CN_DOMAIN_SYSVOL,
  109. FQDN_CN_NTFRS_SETTINGS, // CN_NTFRS_SETTINGS,
  110. FQDN_CN_SYSTEM, // CN_SYSTEM,
  111. FQDN_CN_SUBSCRIPTIONS, // CN_SUBSCRIPTIONS,
  112. FQDN_CN_COMPUTERS, // CN_COMPUTERS
  113. FQDN_MAX_COUNT
  114. } FQDN_ARG_STRING;
  115. PWCHAR FQDN_StdArgTable[FQDN_MAX_COUNT] = {
  116. L"InvalidFqdnArgument",
  117. DsDeleteComputerName,
  118. DsDeleteConfigDn,
  119. L"InvalidFqdnArgument", // Thread->ReplicaSetName,
  120. DsDeleteDefaultDn,
  121. CN_SYSVOLS,
  122. CN_SERVICES,
  123. CN_DOMAIN_SYSVOL,
  124. CN_NTFRS_SETTINGS,
  125. CN_SYSTEM,
  126. CN_SUBSCRIPTIONS,
  127. CN_COMPUTERS
  128. };
  129. typedef struct _FQDN_CONSTRUCTION_TABLE {
  130. PCHAR Description; // For error messages.
  131. PWCHAR Format; // Format string used to construct the FQDN
  132. BYTE Arg[8]; // Array of offsets into the arg table ordered by the FQDN
  133. } FQDN_CONSTRUCTION_TABLE, *PFQDN_CONSTRUCTION_TABLE;
  134. //
  135. // This table describes the FQDNs for FRS objects that need to be deleted.
  136. // The entries contain the object names for both the Beta 2 and Beta 3 versions.
  137. // The objects are deleted in the order specified by the table entries.
  138. //
  139. FQDN_CONSTRUCTION_TABLE FrsDsObjectDeleteTable[] = {
  140. {"MemberDn(B2)", L"cn=%ws,cn=%ws,cn=%ws,cn=%ws,%ws",
  141. FQDN_ComputerName, FQDN_RepSetName, FQDN_CN_SYSVOLS,
  142. FQDN_CN_SERVICES, FQDN_ConfigName, FQDN_END},
  143. {"MemberDn(B3)", L"cn=%ws,cn=%ws,cn=%ws,cn=%ws,%ws",
  144. FQDN_ComputerName, FQDN_CN_DOMAIN_SYSVOL, FQDN_CN_NTFRS_SETTINGS,
  145. FQDN_CN_SYSTEM, FQDN_DefaultDn, FQDN_END},
  146. {"SetDn for(B2)", L"cn=%ws,cn=%ws,cn=%ws,%ws",
  147. FQDN_RepSetName, FQDN_CN_SYSVOLS, FQDN_CN_SERVICES,
  148. FQDN_ConfigName, FQDN_END},
  149. {"SetDn for(B3)", L"cn=%ws,cn=%ws,cn=%ws,%ws",
  150. FQDN_CN_DOMAIN_SYSVOL, FQDN_CN_NTFRS_SETTINGS, FQDN_CN_SYSTEM,
  151. FQDN_DefaultDn, FQDN_END},
  152. {"SettingsDn(B2)", L"cn=%ws,cn=%ws,%ws",
  153. FQDN_CN_SYSVOLS, FQDN_CN_SERVICES, FQDN_ConfigName, FQDN_END},
  154. {"SubscriberDn(B2)", L"cn=%ws,cn=%ws,cn=%ws,cn=%ws,%ws",
  155. FQDN_RepSetName, FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName,
  156. FQDN_CN_COMPUTERS, FQDN_DefaultDn, FQDN_END},
  157. {"SubscriberDn(B3)", L"cn=%ws,cn=%ws,cn=%ws,cn=%ws,%ws",
  158. FQDN_CN_DOMAIN_SYSVOL, FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName,
  159. FQDN_CN_COMPUTERS, FQDN_DefaultDn, FQDN_END},
  160. {"SubscriberDn$(B2)", L"cn=%ws,cn=%ws,cn=%ws$,cn=%ws,%ws",
  161. FQDN_RepSetName, FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName,
  162. FQDN_CN_COMPUTERS, FQDN_DefaultDn, FQDN_END},
  163. {"SubscriberDn$(B3)", L"cn=%ws,cn=%ws,cn=%ws$,cn=%ws,%ws",
  164. FQDN_CN_DOMAIN_SYSVOL, FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName,
  165. FQDN_CN_COMPUTERS, FQDN_DefaultDn, FQDN_END},
  166. {"SubscriptionsDn", L"cn=%ws,cn=%ws,cn=%ws,%ws",
  167. FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName, FQDN_CN_COMPUTERS,
  168. FQDN_DefaultDn, FQDN_END},
  169. {"SubscriptionsDn$", L"cn=%ws,cn=%ws$,cn=%ws,%ws",
  170. FQDN_CN_SUBSCRIPTIONS, FQDN_ComputerName, FQDN_CN_COMPUTERS,
  171. FQDN_DefaultDn, FQDN_END},
  172. {NULL, NULL, FQDN_END}
  173. };
  174. //
  175. // return flags from DsGetDCInfo() & DsGetDcName() too?
  176. //
  177. FLAG_NAME_TABLE NtFrsApi_DsGetDcInfoFlagNameTable[] = {
  178. {DS_PDC_FLAG , "DCisPDCofDomain " },
  179. {DS_GC_FLAG , "DCIsGCofForest " },
  180. {DS_LDAP_FLAG , "ServerSupportsLDAP_Server " },
  181. {DS_DS_FLAG , "DCSupportsDSAndIsA_DC " },
  182. {DS_KDC_FLAG , "DCIsRunningKDCSvc " },
  183. {DS_TIMESERV_FLAG , "DCIsRunningTimeSvc " },
  184. {DS_CLOSEST_FLAG , "DCIsInClosestSiteToClient " },
  185. {DS_WRITABLE_FLAG , "DCHasWritableDS " },
  186. {DS_GOOD_TIMESERV_FLAG , "DCRunningTimeSvcWithClockHW " },
  187. {DS_DNS_CONTROLLER_FLAG , "DCNameIsDNSName " },
  188. {DS_DNS_DOMAIN_FLAG , "DomainNameIsDNSName " },
  189. {DS_DNS_FOREST_FLAG , "DnsForestNameIsDNSName " },
  190. {0, NULL}
  191. };
  192. //
  193. // Note: More replicated friggen code because the build environment for this
  194. // api file is all messed up.
  195. //
  196. VOID
  197. FrsFlagsToStr(
  198. IN DWORD Flags,
  199. IN PFLAG_NAME_TABLE NameTable,
  200. IN ULONG Length,
  201. OUT PSTR Buffer
  202. )
  203. /*++
  204. Routine Description:
  205. Routine to convert a Flags word to a descriptor string using the
  206. supplied NameTable.
  207. Arguments:
  208. Flags - flags to convert.
  209. NameTable - An array of FLAG_NAME_TABLE structs.
  210. Length - Size of buffer in bytes.
  211. Buffer - buffer with returned string.
  212. Return Value:
  213. Buffer containing printable string.
  214. --*/
  215. {
  216. #undef NTFRSAPI_MODULE
  217. #define NTFRSAPI_MODULE "FrsFlagsToStr:"
  218. PFLAG_NAME_TABLE pNT = NameTable;
  219. LONG Remaining = Length-1;
  220. //FRS_ASSERT((Length > 4) && (Buffer != NULL));
  221. *Buffer = '\0';
  222. if (Flags == 0) {
  223. strncpy(Buffer, "<Flags Clear>", Length);
  224. return;
  225. }
  226. //
  227. // Build a string for each bit set in the Flag name table.
  228. //
  229. while ((Flags != 0) && (pNT->Flag != 0)) {
  230. if ((pNT->Flag & Flags) != 0) {
  231. Remaining -= strlen(pNT->Name);
  232. if (Remaining < 0) {
  233. //
  234. // Out of string buffer. Tack a "..." at the end.
  235. //
  236. Remaining += strlen(pNT->Name);
  237. if (Remaining > 3) {
  238. strcat(Buffer, "..." );
  239. } else {
  240. strcpy(&Buffer[Length-4], "...");
  241. }
  242. return;
  243. }
  244. //
  245. // Tack the name onto the buffer and clear the flag bit so we
  246. // know what is left set when we run out of table.
  247. //
  248. strcat(Buffer, pNT->Name);
  249. ClearFlag(Flags, pNT->Flag);
  250. }
  251. pNT += 1;
  252. }
  253. if (Flags != 0) {
  254. //
  255. // If any flags are still set give them back in hex.
  256. //
  257. sprintf( &Buffer[strlen(Buffer)], "0x%08x ", Flags );
  258. }
  259. return;
  260. }
  261. #define NTFRSAPI_DBG_INITIALIZE() NtFrsApi_Dbg_Initialize()
  262. VOID
  263. NtFrsApi_Dbg_Initialize(
  264. VOID
  265. )
  266. /*++
  267. Routine Description:
  268. Initialize the debug subsystem at load.
  269. Arguments:
  270. None.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. InitializeCriticalSection(&NtFrsApi_Dbg_Lock);
  276. }
  277. #define NTFRSAPI_DBG_UNINITIALIZE() NtFrsApi_Dbg_UnInitialize()
  278. VOID
  279. NtFrsApi_Dbg_UnInitialize(
  280. VOID
  281. )
  282. /*++
  283. Routine Description:
  284. Shutdown the debug sunsystem when dll is detached.
  285. Arguments:
  286. None.
  287. Return Value:
  288. None.
  289. --*/
  290. {
  291. DeleteCriticalSection(&NtFrsApi_Dbg_Lock);
  292. }
  293. #define NTFRSAPI_DBG_UNPREPARE() NtFrsApi_Dbg_UnPrepare()
  294. VOID
  295. NtFrsApi_Dbg_UnPrepare(
  296. VOID
  297. )
  298. /*++
  299. Routine Description:
  300. All done; close the debug subsystem.
  301. Arguments:
  302. None.
  303. Return Value:
  304. None.
  305. --*/
  306. {
  307. if (!NtFrsApi_Dbg_LogFILE) {
  308. return;
  309. }
  310. fflush(NtFrsApi_Dbg_LogFILE);
  311. fclose(NtFrsApi_Dbg_LogFILE);
  312. NtFrsApi_Dbg_LogFILE = NULL;
  313. }
  314. #define NTFRSAPI_DBG_FLUSH() NtFrsApi_Dbg_Flush()
  315. VOID
  316. NtFrsApi_Dbg_Flush(
  317. VOID
  318. )
  319. /*++
  320. Routine Description:
  321. Flush the log file.
  322. Arguments:
  323. None.
  324. Return Value:
  325. None.
  326. --*/
  327. {
  328. if (!NtFrsApi_Dbg_LogFILE) {
  329. return;
  330. }
  331. fflush(NtFrsApi_Dbg_LogFILE);
  332. }
  333. BOOL
  334. NtFrsApi_Dbg_FormatLine(
  335. IN PCHAR DebSub,
  336. IN UINT LineNo,
  337. IN PCHAR Line,
  338. IN ULONG LineSize,
  339. IN PUCHAR Format,
  340. IN va_list argptr
  341. )
  342. /*++
  343. Routine Description:
  344. Format the line of debug output.
  345. Arguments:
  346. Not documented.
  347. Return Value:
  348. None.
  349. --*/
  350. {
  351. ULONG LineUsed;
  352. SYSTEMTIME SystemTime;
  353. BOOL Ret = TRUE;
  354. try {
  355. //
  356. // Increment the line count here to prevent counting
  357. // the several DPRINTs that don't have a newline.
  358. //
  359. GetLocalTime(&SystemTime);
  360. if (_snprintf(Line, LineSize, "<%-31s%4u: %5u: %02d:%02d:%02d> ",
  361. (DebSub) ? DebSub : "NoName",
  362. GetCurrentThreadId(),
  363. LineNo,
  364. SystemTime.wHour,
  365. SystemTime.wMinute,
  366. SystemTime.wSecond) < 0) {
  367. Ret = FALSE;
  368. } else {
  369. LineUsed = strlen(Line);
  370. if (((LineUsed + 1) >= LineSize) ||
  371. (_vsnprintf(Line + LineUsed,
  372. LineSize - LineUsed,
  373. Format,
  374. argptr) < 0)) {
  375. Ret = FALSE;
  376. }
  377. }
  378. } except(EXCEPTION_EXECUTE_HANDLER) {
  379. Ret = FALSE;
  380. }
  381. return Ret;
  382. }
  383. #define NTFRSAPI_DBG_PRINT0(_Format) \
  384. NtFrsApi_Dbg_Print((PUCHAR)_Format, NTFRSAPI_MODULE, __LINE__)
  385. #define NTFRSAPI_DBG_PRINT1(_Format, _p1) \
  386. NtFrsApi_Dbg_Print((PUCHAR)_Format, NTFRSAPI_MODULE, __LINE__, \
  387. _p1)
  388. #define NTFRSAPI_DBG_PRINT2(_Format, _p1, _p2) \
  389. NtFrsApi_Dbg_Print((PUCHAR)_Format, NTFRSAPI_MODULE, __LINE__, \
  390. _p1, _p2)
  391. #define NTFRSAPI_DBG_PRINT3(_Format, _p1, _p2, _p3) \
  392. NtFrsApi_Dbg_Print((PUCHAR)_Format, NTFRSAPI_MODULE, __LINE__, \
  393. _p1, _p2, _p3)
  394. #define NTFRSAPI_DBG_PRINT4(_Format, _p1, _p2, _p3, _p4) \
  395. NtFrsApi_Dbg_Print((PUCHAR)_Format, NTFRSAPI_MODULE, __LINE__, \
  396. _p1, _p2, _p3, _p4)
  397. VOID
  398. NtFrsApi_Dbg_Print(
  399. IN PUCHAR Format,
  400. IN PCHAR DebSub,
  401. IN UINT LineNo,
  402. IN ... )
  403. /*++
  404. Routine Description:
  405. Format and print a line of debug output to the log file.
  406. Arguments:
  407. Format - printf format
  408. DebSub - module name
  409. LineNo - file's line number
  410. Return Value:
  411. None.
  412. --*/
  413. {
  414. CHAR Line[512];
  415. //
  416. // varargs stuff
  417. //
  418. va_list argptr;
  419. va_start(argptr, LineNo);
  420. //
  421. // Print the line to the log file
  422. //
  423. try {
  424. EnterCriticalSection(&NtFrsApi_Dbg_Lock);
  425. if (NtFrsApi_Dbg_LogFILE) {
  426. if (NtFrsApi_Dbg_FormatLine(DebSub, LineNo, Line, sizeof(Line),
  427. Format, argptr)) {
  428. fprintf(NtFrsApi_Dbg_LogFILE, "%s", Line);
  429. fflush(NtFrsApi_Dbg_LogFILE);
  430. }
  431. }
  432. } finally {
  433. LeaveCriticalSection(&NtFrsApi_Dbg_Lock);
  434. }
  435. va_end(argptr);
  436. }
  437. #define NTFRSAPI_DBG_PREPARE() NtFrsApi_Dbg_Prepare()
  438. VOID
  439. NtFrsApi_Dbg_Prepare(
  440. VOID
  441. )
  442. /*++
  443. Routine Description:
  444. Prepare the debug subsystem at NtFrsApi_Prepare().
  445. Arguments:
  446. None.
  447. Return Value:
  448. None.
  449. --*/
  450. {
  451. #undef NTFRSAPI_MODULE
  452. #define NTFRSAPI_MODULE "NtFrsApi_Dbg_Prepare:"
  453. DWORD WStatus;
  454. DWORD Len;
  455. WCHAR TimeBuf[MAX_PATH];
  456. Len = ExpandEnvironmentStrings(NTFRSAPI_DBG_LOG_DIR,
  457. NtFrsApi_Dbg_LogFile,
  458. MAX_PATH + 1);
  459. if (Len == 0) {
  460. return;
  461. }
  462. //
  463. // Create the debug directory
  464. //
  465. if (!CreateDirectory(NtFrsApi_Dbg_LogFile, NULL)) {
  466. WStatus = GetLastError();
  467. if (!WIN_ALREADY_EXISTS(WStatus)) {
  468. return;
  469. }
  470. }
  471. wcscat(NtFrsApi_Dbg_LogFile, NTFRSAPI_DBG_LOG_FILE);
  472. NtFrsApi_Dbg_LogFILE = _wfopen(NtFrsApi_Dbg_LogFile, L"ac");
  473. if (!NtFrsApi_Dbg_LogFILE) {
  474. return;
  475. }
  476. TimeBuf[0] = L'\0';
  477. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, TimeBuf, MAX_PATH);
  478. }
  479. #define NTFRSAPI_IPRINT0(_Info, _Format) \
  480. NtFrsApi_Iprint(_Info, _Format)
  481. #define NTFRSAPI_IPRINT1(_Info, _Format, _p1) \
  482. NtFrsApi_Iprint(_Info, _Format, _p1)
  483. #define NTFRSAPI_IPRINT2(_Info, _Format, _p1, _p2) \
  484. NtFrsApi_Iprint(_Info, _Format, _p1, _p2)
  485. #define NTFRSAPI_IPRINT3(_Info, _Format, _p1, _p2, _p3) \
  486. NtFrsApi_Iprint(_Info, _Format, _p1, _p2, _p3)
  487. #define NTFRSAPI_IPRINT4(_Info, _Format, _p1, _p2, _p3, _p4) \
  488. NtFrsApi_Iprint(_Info, _Format, _p1, _p2, _p3, _p4)
  489. #define NTFRSAPI_IPRINT5(_Info, _Format, _p1, _p2, _p3, _p4, _p5) \
  490. NtFrsApi_Iprint(_Info, _Format, _p1, _p2, _p3, _p4, _p5)
  491. #define NTFRSAPI_IPRINT6(_Info, _Format, _p1, _p2, _p3, _p4, _p5, _p6) \
  492. NtFrsApi_Iprint(_Info, _Format, _p1, _p2, _p3, _p4, _p5, _p6)
  493. #define NTFRSAPI_IPRINT7(_Info, _Format, _p1, _p2, _p3, _p4, _p5, _p6, _p7) \
  494. NtFrsApi_Iprint(_Info, _Format, _p1, _p2, _p3, _p4, _p5, _p6, _p7)
  495. VOID
  496. NtFrsApi_Iprint(
  497. IN PNTFRSAPI_INFO Info,
  498. IN PCHAR Format,
  499. IN ... )
  500. /*++
  501. Routine Description:
  502. Format and print a line of information output into the info buffer.
  503. Arguments:
  504. Info - Info buffer
  505. Format - printf format
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. PCHAR Line;
  511. ULONG LineLen;
  512. LONG LineSize;
  513. //
  514. // varargs stuff
  515. //
  516. va_list argptr;
  517. va_start(argptr, Format);
  518. //
  519. // Print the line into the info buffer
  520. //
  521. try {
  522. if (!FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  523. Line = ((PCHAR)Info) + Info->OffsetToFree;
  524. LineSize = (Info->SizeInChars - (ULONG)(Line - (PCHAR)Info)) - 1;
  525. if (LineSize <= 0 ||
  526. _vsnprintf(Line, LineSize, Format, argptr) < 0) {
  527. SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL);
  528. } else {
  529. LineLen = strlen(Line) + 1;
  530. if (Info->CharsToSkip) {
  531. if (LineLen > Info->CharsToSkip) {
  532. Info->CharsToSkip = 0;
  533. } else {
  534. Info->CharsToSkip -= LineLen;
  535. }
  536. } else {
  537. Info->OffsetToFree += LineLen;
  538. Info->TotalChars += LineLen;
  539. }
  540. }
  541. }
  542. } except(EXCEPTION_EXECUTE_HANDLER) {
  543. }
  544. va_end(argptr);
  545. }
  546. BOOL
  547. NtFrsApiCheckRpcError(
  548. RPC_STATUS RStatus,
  549. PCHAR Msg
  550. )
  551. /*++
  552. Routine Description:
  553. Print rpc error message
  554. Arguments:
  555. RStatus - Status return from RPC call.
  556. Msg - message string. Optional.
  557. Return Value:
  558. True if there is an error else False.
  559. --*/
  560. {
  561. #undef NTFRSAPI_MODULE
  562. #define NTFRSAPI_MODULE "NtFrsApiCheckRpcError:"
  563. if (RStatus != RPC_S_OK) {
  564. if (Msg != NULL) {
  565. NTFRSAPI_DBG_PRINT2("RpcError (%d) - %s\n", RStatus, Msg);
  566. }
  567. return TRUE;
  568. }
  569. return FALSE;
  570. }
  571. DWORD
  572. NtFrsApi_Fix_Comm_WStatus(
  573. IN DWORD WStatus
  574. )
  575. /*++
  576. Routine Description:
  577. If WStatus is an FRS error code, return it unaltered. Otherwise,
  578. map the rpc status into the generic FRS_ERR_SERVICE_COMM.
  579. Arguments:
  580. WStatus - status from the rpc call.
  581. Return Value:
  582. Fixed WStatus
  583. --*/
  584. {
  585. #undef NTFRSAPI_MODULE
  586. #define NTFRSAPI_MODULE "NtFrsApi_Fix_Comm_WStatus:"
  587. // TODO: replace these constants with symbollic values from winerror.h
  588. if ( (WStatus < 8000) || (WStatus >= 8200) ) {
  589. NTFRSAPI_DBG_PRINT1("Comm WStatus: not FRS (%d)\n", WStatus);
  590. WStatus = FRS_ERR_SERVICE_COMM;
  591. }
  592. return WStatus;
  593. }
  594. PVOID
  595. NtFrsApi_Alloc(
  596. IN DWORD Size
  597. )
  598. /*++
  599. Routine Description:
  600. Allocate fixed, zeroed memory. Raise an exception if memory
  601. cannot be allocated.
  602. Arguments:
  603. Size - size of memory request
  604. Return Value:
  605. Raise an exception if memory cannot be allocated.
  606. --*/
  607. {
  608. PVOID Va;
  609. Va = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, Size);
  610. if (!Va) {
  611. RaiseException(GetLastError(), 0, 0, NULL);
  612. }
  613. return Va;
  614. }
  615. HANDLE
  616. NtFrsApi_CreateEvent(
  617. IN BOOL ManualReset,
  618. IN BOOL InitialState
  619. )
  620. /*++
  621. Routine Description:
  622. Support routine to create an event.
  623. Arguments:
  624. ManualReset - TRUE if ResetEvent is required
  625. InitialState - TRUE if signaled
  626. Return Value:
  627. Address of the created event handle.
  628. --*/
  629. {
  630. HANDLE Handle;
  631. Handle = CreateEvent(NULL, ManualReset, InitialState, NULL);
  632. if (!HANDLE_IS_VALID(Handle)) {
  633. RaiseException(GetLastError(), 0, 0, NULL);
  634. }
  635. return Handle;
  636. }
  637. PWCHAR
  638. NtFrsApi_Dup(
  639. IN PWCHAR Src
  640. )
  641. /*++
  642. Routine Description:
  643. Duplicate the string. Raise an exception if memory cannot be allocated.
  644. Arguments:
  645. Size - size of memory request
  646. Return Value:
  647. Raise an exception if memory cannot be allocated.
  648. --*/
  649. {
  650. PWCHAR Dst;
  651. DWORD Size;
  652. if (!Src) {
  653. return NULL;
  654. }
  655. Size = (wcslen(Src) + 1) * sizeof(WCHAR);
  656. Dst = NtFrsApi_Alloc(Size);
  657. CopyMemory(Dst, Src, Size);
  658. return Dst;
  659. }
  660. #define NTFRSAPI_ERROR_MESSAGE_DELIMITER L": "
  661. VOID
  662. WINAPI
  663. NtFrsApi_CallBackOnWStatus(
  664. IN DWORD (*ErrorCallBack)(IN PWCHAR, IN ULONG), OPTIONAL
  665. IN PWCHAR ObjectName, OPTIONAL
  666. IN DWORD WStatus
  667. )
  668. /*++
  669. Routine Description:
  670. Arguments:
  671. Return Value:
  672. --*/
  673. {
  674. #undef NTFRSAPI_MODULE
  675. #define NTFRSAPI_MODULE "NtFrsApi_CallBackOnWStatus:"
  676. DWORD MsgBufSize;
  677. DWORD FinalSize;
  678. PWCHAR FinalMsg = NULL;
  679. WCHAR MsgBuf[MAX_PATH + 1];
  680. //
  681. // Nothing to report
  682. //
  683. if (!ObjectName || !ErrorCallBack) {
  684. return;
  685. }
  686. //
  687. // Format the error code
  688. //
  689. MsgBufSize = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  690. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  691. NULL,
  692. WStatus,
  693. 0,
  694. MsgBuf,
  695. MAX_PATH + 1,
  696. NULL);
  697. if (!MsgBufSize) {
  698. return;
  699. }
  700. //
  701. // Produce message: "ObjectName: Error Code Message"
  702. //
  703. FinalSize = (wcslen(ObjectName) +
  704. wcslen(MsgBuf) +
  705. wcslen(NTFRSAPI_ERROR_MESSAGE_DELIMITER) +
  706. 1) * sizeof(WCHAR);
  707. FinalMsg = NtFrsApi_Alloc(FinalSize);
  708. FinalMsg[0] = L'\0';
  709. wcscat(FinalMsg, ObjectName);
  710. wcscat(FinalMsg, NTFRSAPI_ERROR_MESSAGE_DELIMITER);
  711. wcscat(FinalMsg, MsgBuf);
  712. //
  713. // Record message with caller
  714. //
  715. (ErrorCallBack)(FinalMsg, WStatus);
  716. FREE(FinalMsg);
  717. }
  718. //
  719. // NTFRSAPI Thread Struct
  720. //
  721. typedef struct _NTFRSAPI_THREAD NTFRSAPI_THREAD, *PNTFRSAPI_THREAD;
  722. struct _NTFRSAPI_THREAD {
  723. //
  724. // Thread state
  725. //
  726. PNTFRSAPI_THREAD Next; // Singly linked list
  727. HANDLE ThreadHandle; // returned by CreateThread()
  728. DWORD ThreadId; // returned by CreateThread()
  729. HANDLE DoneEvent; // Set when thread is done
  730. DWORD ThreadWStatus; // Win32 Status of this thread
  731. //
  732. // From NtFrs Service
  733. //
  734. ULONG ServiceState; // State of promotion/demotion
  735. ULONG ServiceWStatus; // Win32 Status of promotion/demotion
  736. PWCHAR ServiceDisplay; // Display string
  737. //
  738. // From NtFrsApi_StartPromotion/Demotion
  739. //
  740. PWCHAR ParentComputer;
  741. PWCHAR ParentAccount;
  742. PWCHAR ParentPassword;
  743. DWORD (*DisplayCallBack)(IN PWCHAR Display);
  744. DWORD (*ErrorCallBack)(IN PWCHAR, IN ULONG);
  745. PWCHAR ReplicaSetName;
  746. PWCHAR ReplicaSetType;
  747. DWORD ReplicaSetPrimary;
  748. PWCHAR ReplicaSetStage;
  749. PWCHAR ReplicaSetRoot;
  750. } *NtFrsApi_Threads;
  751. DWORD NtFrsApi_NumberOfThreads;
  752. PVOID
  753. NtFrsApi_FreeThread(
  754. IN PNTFRSAPI_THREAD Thread
  755. )
  756. /*++
  757. Routine Description:
  758. Abort a thread and free its thread struct.
  759. Caller must hold the NtFrsApi_TheadLock.
  760. Arguments:
  761. Thread - represents the thread
  762. Return Value:
  763. NULL
  764. --*/
  765. {
  766. //
  767. // Clean up the handles
  768. // Cancel the RPC requests.
  769. // Give the thread a little time to clean up.
  770. // Terminate the thread.
  771. // Set and close the thread's done event.
  772. //
  773. if (HANDLE_IS_VALID(Thread->ThreadHandle)) {
  774. RpcCancelThread(Thread->ThreadHandle);
  775. WaitForSingleObject(Thread->ThreadHandle, 5 * 1000);
  776. TerminateThread(Thread->ThreadHandle, ERROR_OPERATION_ABORTED);
  777. CloseHandle(Thread->ThreadHandle);
  778. }
  779. if (HANDLE_IS_VALID(Thread->DoneEvent)) {
  780. SetEvent(Thread->DoneEvent);
  781. CloseHandle(Thread->DoneEvent);
  782. }
  783. //
  784. // One less thread
  785. //
  786. --NtFrsApi_NumberOfThreads;
  787. //
  788. // Clean up memory
  789. //
  790. FREE(Thread->ParentComputer);
  791. FREE(Thread->ParentAccount);
  792. FREE(Thread->ParentPassword);
  793. FREE(Thread->ReplicaSetName);
  794. FREE(Thread->ReplicaSetType);
  795. FREE(Thread->ReplicaSetStage);
  796. FREE(Thread->ReplicaSetRoot);
  797. FREE(Thread);
  798. return NULL;
  799. }
  800. DWORD
  801. NtFrsApi_CreateThread(
  802. IN DWORD Entry(IN PVOID Arg),
  803. IN PWCHAR ParentComputer,
  804. IN PWCHAR ParentAccount,
  805. IN PWCHAR ParentPassword,
  806. IN DWORD DisplayCallBack(IN PWCHAR Display),
  807. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG),
  808. IN PWCHAR ReplicaSetName,
  809. IN PWCHAR ReplicaSetType,
  810. IN DWORD ReplicaSetPrimary,
  811. IN PWCHAR ReplicaSetStage,
  812. IN PWCHAR ReplicaSetRoot
  813. )
  814. /*++
  815. Routine Description:
  816. Create a thread for promotion/demotion.
  817. Arguments:
  818. Entry - Entry function
  819. ParentComputer - An RPC-bindable name of the computer that is
  820. supplying the Directory Service (DS) with its
  821. initial state. The files and directories for
  822. the system volume are replicated from this
  823. parent computer.
  824. ParentAccount - A logon account on ParentComputer.
  825. ParentPassword - The logon account's password on ParentComputer.
  826. DisplayCallBack - Called peridically with a progress display.
  827. ErrorCallBack - Called with additional error info
  828. ReplicaSetName - Name of the replica set.
  829. ReplicaSetType - Type of replica set (enterprise or domain)
  830. ReplicaSetPrimary - Is this the primary member of the replica set?
  831. ReplicaSetStage - Staging path.
  832. ReplicaSetRoot - Root path.
  833. Return Value:
  834. Win32 Status
  835. --*/
  836. {
  837. DWORD WStatus;
  838. PNTFRSAPI_THREAD Thread;
  839. try {
  840. //
  841. // Allocate a local thread structure
  842. //
  843. Thread = NtFrsApi_Alloc(sizeof(NTFRSAPI_THREAD));
  844. //
  845. // Thread sets this event when it is done.
  846. //
  847. Thread->DoneEvent = NtFrsApi_CreateEvent(TRUE, FALSE);
  848. Thread->ParentComputer = NtFrsApi_Dup(ParentComputer);
  849. Thread->ParentAccount = NtFrsApi_Dup(ParentAccount);
  850. Thread->ParentPassword = NtFrsApi_Dup(ParentPassword);
  851. Thread->DisplayCallBack = DisplayCallBack;
  852. Thread->ErrorCallBack = ErrorCallBack;
  853. Thread->ReplicaSetName = NtFrsApi_Dup(ReplicaSetName);
  854. Thread->ReplicaSetType = NtFrsApi_Dup(ReplicaSetType);
  855. Thread->ReplicaSetPrimary = ReplicaSetPrimary;
  856. Thread->ReplicaSetStage = NtFrsApi_Dup(ReplicaSetStage);
  857. Thread->ReplicaSetRoot = NtFrsApi_Dup(ReplicaSetRoot);
  858. Thread->ThreadWStatus = ERROR_SUCCESS;
  859. Thread->ServiceWStatus = ERROR_SUCCESS;
  860. Thread->ServiceState = NTFRSAPI_SERVICE_STATE_IS_UNKNOWN;
  861. //
  862. // Kick off the thread
  863. //
  864. Thread->ThreadHandle = (HANDLE) CreateThread(NULL,
  865. 10000,
  866. Entry,
  867. (PVOID)Thread,
  868. 0,
  869. &Thread->ThreadId);
  870. //
  871. // FAILED
  872. //
  873. if (!HANDLE_IS_VALID(Thread->ThreadHandle)) {
  874. WStatus = GetLastError();
  875. NTFRSAPI_DBG_PRINT1("CreateThread(); %d\n", WStatus);
  876. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  877. }
  878. //
  879. // SUCCEEDED
  880. //
  881. EnterCriticalSection(&NtFrsApi_ThreadLock);
  882. ++NtFrsApi_NumberOfThreads;
  883. Thread->Next = NtFrsApi_Threads;
  884. NtFrsApi_Threads = Thread;
  885. Thread = NULL;
  886. LeaveCriticalSection(&NtFrsApi_ThreadLock);
  887. WStatus = ERROR_SUCCESS;
  888. CLEANUP:;
  889. } except (EXCEPTION_EXECUTE_HANDLER) {
  890. GET_EXCEPTION_CODE(WStatus);
  891. }
  892. //
  893. // Clean up any handles, events, memory, ...
  894. //
  895. try {
  896. if (Thread) {
  897. Thread = NtFrsApi_FreeThread(Thread);
  898. }
  899. } except (EXCEPTION_EXECUTE_HANDLER) {
  900. GET_EXCEPTION_CODE(WStatus);
  901. }
  902. return WStatus;
  903. }
  904. PWCHAR
  905. NtFrsApi_FrsGetResourceStr(
  906. IN HINSTANCE hInstance,
  907. IN LONG Id
  908. )
  909. /*++
  910. Routine Description:
  911. This routine Loads the specified resource string.
  912. It allocates a buffer and returns the ptr.
  913. Arguments:
  914. Id - An FRS_IDS_xxx identifier.
  915. Return Value:
  916. Ptr to allocated string.
  917. The caller must free the buffer with a call to FrsFree().
  918. --*/
  919. #undef NTFRSAPI_MODULE
  920. #define NTFRSAPI_MODULE "NtFrsApi_FrsGetResourceStr:"
  921. {
  922. LONG N;
  923. WCHAR WStr[200];
  924. //
  925. // ID Must be Valid.
  926. //
  927. if ((Id <= IDS_TABLE_START) || (Id >= IDS_TABLE_END)) {
  928. NTFRSAPI_DBG_PRINT1("Resource string ID is out of range - %d\n", Id);
  929. Id = IDS_MISSING_STRING;
  930. }
  931. WStr[0] = UNICODE_NULL;
  932. N = LoadString(hInstance, Id, WStr, sizeof(WStr)/sizeof(WCHAR));
  933. if (N == 0) {
  934. NTFRSAPI_DBG_PRINT1("ERROR - Failed to get resource string. WStatus = %d\n",
  935. GetLastError());
  936. }
  937. return NtFrsApi_Dup(WStr);
  938. }
  939. BOOL
  940. WINAPI
  941. NtFrsApi_Initialize(
  942. HINSTANCE hinstDLL,
  943. DWORD fdwReason,
  944. LPVOID lpvReserved
  945. )
  946. /*++
  947. Routine Description:
  948. Called when this DLL is attached and detached.
  949. Arguments:
  950. hinstDLL handle to DLL module
  951. fdwReason reason for calling function
  952. lpvReserved reserved
  953. Return Value:
  954. TRUE - no problems
  955. FALSE - DLL is not attached
  956. --*/
  957. {
  958. switch (fdwReason) {
  959. case DLL_PROCESS_ATTACH :
  960. //
  961. // No initialization needed per thread
  962. //
  963. DisableThreadLibraryCalls(hinstDLL);
  964. //
  965. // Get the translated long service name for error messages.
  966. //
  967. NtFrsApi_ServiceLongName =
  968. NtFrsApi_FrsGetResourceStr(hinstDLL, IDS_SERVICE_LONG_NAME);
  969. //
  970. // Shutdown event
  971. //
  972. NtFrsApi_ShutDownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  973. if (!HANDLE_IS_VALID(NtFrsApi_ShutDownEvent)) {
  974. return FALSE;
  975. }
  976. //
  977. // General purpose critical section
  978. //
  979. InitializeCriticalSection(&NtFrsApi_GlobalLock);
  980. //
  981. // Thread subsystem
  982. //
  983. InitializeCriticalSection(&NtFrsApi_ThreadLock);
  984. //
  985. // Debug subsystem
  986. //
  987. NTFRSAPI_DBG_INITIALIZE();
  988. //
  989. // Not prepared for promotion or demotion, yet
  990. //
  991. NtFrsApi_State = NTFRSAPI_LOADED;
  992. break;
  993. case DLL_THREAD_ATTACH :
  994. break;
  995. case DLL_THREAD_DETACH :
  996. break;
  997. case DLL_PROCESS_DETACH :
  998. FREE(NtFrsApi_ServiceLongName);
  999. DeleteCriticalSection(&NtFrsApi_GlobalLock);
  1000. DeleteCriticalSection(&NtFrsApi_ThreadLock);
  1001. if (NtFrsApi_ShutDownEvent) {
  1002. CloseHandle(NtFrsApi_ShutDownEvent);
  1003. }
  1004. NTFRSAPI_DBG_UNINITIALIZE();
  1005. break;
  1006. default:
  1007. return FALSE;
  1008. }
  1009. return TRUE;
  1010. }
  1011. PVOID
  1012. MIDL_user_allocate(
  1013. IN size_t Bytes
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Allocate memory for RPC.
  1018. Arguments:
  1019. Bytes - Number of bytes to allocate.
  1020. Return Value:
  1021. NULL - memory could not be allocated.
  1022. !NULL - address of allocated memory.
  1023. --*/
  1024. {
  1025. return LocalAlloc(LMEM_FIXED, Bytes);
  1026. }
  1027. VOID
  1028. MIDL_user_free(
  1029. IN PVOID Buffer
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. Free memory for RPC.
  1034. Arguments:
  1035. Buffer - Address of memory allocated with MIDL_user_allocate().
  1036. Return Value:
  1037. None.
  1038. --*/
  1039. {
  1040. FREE(Buffer);
  1041. }
  1042. DWORD
  1043. WINAPI
  1044. NtFrsApi_Bind(
  1045. IN PWCHAR ComputerName, OPTIONAL
  1046. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1047. OUT handle_t *OutHandle
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Bind to the NtFrs service on ComputerName (this machine if NULL).
  1052. Arguments:
  1053. ComputerName - Bind to the service on this computer. The computer
  1054. name can be any RPC-bindable name. Usually, the
  1055. NetBIOS or DNS name works just fine. The NetBIOS
  1056. name can be found with GetComputerName() or
  1057. hostname. The DNS name can be found with
  1058. gethostbyname() or ipconfig /all. If NULL, the
  1059. service on this computer is contacted. The service
  1060. is contacted using Secure RPC.
  1061. ErrorCallBack - Ignored if NULL. Otherwise called with extra info
  1062. about an error.
  1063. OutHandle - Bound, resolved, authenticated handle
  1064. Return Value:
  1065. Win32 Status
  1066. --*/
  1067. {
  1068. #undef NTFRSAPI_MODULE
  1069. #define NTFRSAPI_MODULE "NtFrsApi_Bind:"
  1070. DWORD WStatus, WStatus1;
  1071. DWORD ComputerLen;
  1072. handle_t Handle = NULL;
  1073. PWCHAR LocalName = NULL;
  1074. PWCHAR BindingString = NULL;
  1075. try {
  1076. NTFRSAPI_DBG_PRINT1("Bind: %ws\n", ComputerName);
  1077. //
  1078. // Return value
  1079. //
  1080. *OutHandle = NULL;
  1081. //
  1082. // If needed, get computer name
  1083. //
  1084. if (ComputerName == NULL) {
  1085. ComputerLen = MAX_COMPUTERNAME_LENGTH + 2;
  1086. LocalName = NtFrsApi_Alloc(ComputerLen * sizeof(WCHAR));
  1087. if (!GetComputerName(LocalName, &ComputerLen)) {
  1088. WStatus = GetLastError();
  1089. NTFRSAPI_DBG_PRINT1("Bind: GetComputerName(); %d\n", WStatus);
  1090. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1091. }
  1092. ComputerName = LocalName;
  1093. }
  1094. //
  1095. // Create a binding string to NtFrs on some machine. Trim leading \\
  1096. //
  1097. FRS_TRIM_LEADING_2SLASH(ComputerName);
  1098. NTFRSAPI_DBG_PRINT1("Bind: compose to %ws\n", ComputerName);
  1099. WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, ComputerName,
  1100. NULL, NULL, &BindingString);
  1101. NTFRSAPI_DBG_PRINT2("Bind: compose done to %ws; %d\n", ComputerName, WStatus);
  1102. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1103. //
  1104. // Store the binding in the handle
  1105. //
  1106. WStatus = RpcBindingFromStringBinding(BindingString, &Handle);
  1107. if (!WIN_SUCCESS(WStatus)) {
  1108. NTFRSAPI_DBG_PRINT2("Bind: RpcBindingFromStringBinding(%ws); %d\n",
  1109. ComputerName, WStatus);
  1110. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1111. }
  1112. //
  1113. // Resolve the binding to the dynamic endpoint
  1114. //
  1115. NTFRSAPI_DBG_PRINT1("Bind: resolve to %ws\n", ComputerName);
  1116. WStatus = RpcEpResolveBinding(Handle, NtFrsApi_ClientIfHandle);
  1117. NTFRSAPI_DBG_PRINT2("Bind: resolve done to %ws; %d\n", ComputerName, WStatus);
  1118. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1119. //
  1120. // SUCCESS
  1121. //
  1122. *OutHandle = Handle;
  1123. Handle = NULL;
  1124. WStatus = ERROR_SUCCESS;
  1125. cleanup:;
  1126. } except (EXCEPTION_EXECUTE_HANDLER) {
  1127. GET_EXCEPTION_CODE(WStatus);
  1128. }
  1129. //
  1130. // Clean up any handles, events, memory, ...
  1131. //
  1132. try {
  1133. if (LocalName) {
  1134. FREE(LocalName);
  1135. }
  1136. if (BindingString) {
  1137. WStatus1 = RpcStringFreeW(&BindingString);
  1138. NtFrsApiCheckRpcError(WStatus1, "RpcStringFreeW");
  1139. }
  1140. if (Handle) {
  1141. WStatus1 = RpcBindingFree(&Handle);
  1142. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  1143. }
  1144. } except (EXCEPTION_EXECUTE_HANDLER) {
  1145. GET_EXCEPTION_CODE(WStatus);
  1146. }
  1147. NTFRSAPI_DBG_PRINT1("Bind done: %d\n", WStatus);
  1148. return WStatus;
  1149. }
  1150. DWORD
  1151. WINAPI
  1152. NtFrsApi_BindWithAuth(
  1153. IN PWCHAR ComputerName, OPTIONAL
  1154. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1155. OUT handle_t *OutHandle
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Bind to the NtFrs service on ComputerName (this machine if NULL)
  1160. with authenticated, encrypted packets.
  1161. Arguments:
  1162. ComputerName - Bind to the service on this computer. The computer
  1163. name can be any RPC-bindable name. Usually, the
  1164. NetBIOS or DNS name works just fine. The NetBIOS
  1165. name can be found with GetComputerName() or
  1166. hostname. The DNS name can be found with
  1167. gethostbyname() or ipconfig /all. If NULL, the
  1168. service on this computer is contacted. The service
  1169. is contacted using Secure RPC.
  1170. ErrorCallBack - Ignored if NULL. Otherwise called with extra info
  1171. about an error.
  1172. OutHandle - Bound, resolved, authenticated handle
  1173. Return Value:
  1174. Win32 Status
  1175. --*/
  1176. {
  1177. #undef NTFRSAPI_MODULE
  1178. #define NTFRSAPI_MODULE "NtFrsApi_BindWithAuth:"
  1179. DWORD WStatus, WStatus1;
  1180. DWORD ComputerLen;
  1181. handle_t Handle = NULL;
  1182. PWCHAR LocalName = NULL;
  1183. PWCHAR PrincName = NULL;
  1184. PWCHAR BindingString = NULL;
  1185. try {
  1186. NTFRSAPI_DBG_PRINT1("Bind With Auth: %ws\n", ComputerName);
  1187. //
  1188. // Return value
  1189. //
  1190. *OutHandle = NULL;
  1191. //
  1192. // If needed, get computer name
  1193. //
  1194. if (ComputerName == NULL) {
  1195. ComputerLen = MAX_COMPUTERNAME_LENGTH + 2;
  1196. LocalName = NtFrsApi_Alloc(ComputerLen * sizeof(WCHAR));
  1197. if (!GetComputerName(LocalName, &ComputerLen)) {
  1198. WStatus = GetLastError();
  1199. NTFRSAPI_DBG_PRINT1("Bind With Auth: GetComputerName(); %d\n", WStatus);
  1200. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1201. }
  1202. ComputerName = LocalName;
  1203. }
  1204. //
  1205. // Create a binding string to NtFrs on some machine. Trim leading \\
  1206. //
  1207. FRS_TRIM_LEADING_2SLASH(ComputerName);
  1208. NTFRSAPI_DBG_PRINT1("Bind With Auth: compose to %ws\n", ComputerName);
  1209. WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, ComputerName,
  1210. NULL, NULL, &BindingString);
  1211. NTFRSAPI_DBG_PRINT2("Bind With Auth: compose done to %ws; %d\n", ComputerName, WStatus);
  1212. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1213. //
  1214. // Store the binding in the handle
  1215. //
  1216. WStatus = RpcBindingFromStringBinding(BindingString, &Handle);
  1217. if (!WIN_SUCCESS(WStatus)) {
  1218. NTFRSAPI_DBG_PRINT2("Bind With Auth: RpcBindingFromStringBinding(%ws); %d\n",
  1219. ComputerName, WStatus);
  1220. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1221. }
  1222. //
  1223. // Resolve the binding to the dynamic endpoint
  1224. //
  1225. NTFRSAPI_DBG_PRINT1("Bind With Auth: resolve to %ws\n", ComputerName);
  1226. WStatus = RpcEpResolveBinding(Handle, NtFrsApi_ClientIfHandle);
  1227. NTFRSAPI_DBG_PRINT2("Bind With Auth: resolve done to %ws; %d\n", ComputerName, WStatus);
  1228. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1229. //
  1230. // Find the principle name
  1231. //
  1232. NTFRSAPI_DBG_PRINT1("Bind With Auth: princname to %ws\n", ComputerName);
  1233. WStatus = RpcMgmtInqServerPrincName(Handle, RPC_C_AUTHN_GSS_NEGOTIATE, &PrincName);
  1234. NTFRSAPI_DBG_PRINT2("Bind With Auth: princname done to %ws; %d\n", ComputerName, WStatus);
  1235. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1236. //
  1237. // Set authentication info
  1238. //
  1239. NTFRSAPI_DBG_PRINT2("Bind With Auth: auth to %ws (princname %ws)\n",
  1240. ComputerName, PrincName);
  1241. WStatus = RpcBindingSetAuthInfo(Handle,
  1242. PrincName,
  1243. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  1244. RPC_C_AUTHN_GSS_NEGOTIATE,
  1245. NULL,
  1246. RPC_C_AUTHZ_NONE);
  1247. NTFRSAPI_DBG_PRINT2("Bind With Auth: set auth done to %ws; %d\n", ComputerName, WStatus);
  1248. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1249. //
  1250. // SUCCESS
  1251. //
  1252. *OutHandle = Handle;
  1253. Handle = NULL;
  1254. WStatus = ERROR_SUCCESS;
  1255. CLEANUP:;
  1256. } except (EXCEPTION_EXECUTE_HANDLER) {
  1257. //
  1258. // Exception (may be RPC)
  1259. //
  1260. GET_EXCEPTION_CODE(WStatus);
  1261. }
  1262. //
  1263. // Clean up any handles, events, memory, ...
  1264. //
  1265. try {
  1266. if (LocalName) {
  1267. FREE(LocalName);
  1268. }
  1269. if (BindingString) {
  1270. WStatus1 = RpcStringFreeW(&BindingString);
  1271. NtFrsApiCheckRpcError(WStatus1, "RpcStringFreeW");
  1272. }
  1273. if (PrincName) {
  1274. RpcStringFree(&PrincName);
  1275. }
  1276. if (Handle) {
  1277. WStatus1 = RpcBindingFree(&Handle);
  1278. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  1279. }
  1280. } except (EXCEPTION_EXECUTE_HANDLER) {
  1281. //
  1282. // Exception (may be RPC)
  1283. //
  1284. GET_EXCEPTION_CODE(WStatus);
  1285. }
  1286. NTFRSAPI_DBG_PRINT1("Bind With Auth done: %d\n", WStatus);
  1287. return WStatus;
  1288. }
  1289. DWORD
  1290. WINAPI
  1291. NtFrsApi_BindForDcpromo(
  1292. IN PWCHAR ComputerName, OPTIONAL
  1293. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1294. OUT handle_t *OutHandle
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Bind to the NtFrs service on ComputerName (this machine if NULL)
  1299. with packets capable of being impersonated.
  1300. Arguments:
  1301. ComputerName - Bind to the service on this computer. The computer
  1302. name can be any RPC-bindable name. Usually, the
  1303. NetBIOS or DNS name works just fine. The NetBIOS
  1304. name can be found with GetComputerName() or
  1305. hostname. The DNS name can be found with
  1306. gethostbyname() or ipconfig /all. If NULL, the
  1307. service on this computer is contacted. The service
  1308. is contacted using Secure RPC.
  1309. ErrorCallBack - Ignored if NULL. Otherwise called with extra info
  1310. about an error.
  1311. OutHandle - Bound, resolved, authenticated handle
  1312. Return Value:
  1313. Win32 Status
  1314. --*/
  1315. {
  1316. #undef NTFRSAPI_MODULE
  1317. #define NTFRSAPI_MODULE "NtFrsApi_BindForDcpromo:"
  1318. DWORD WStatus, WStatus1;
  1319. DWORD ComputerLen;
  1320. handle_t Handle = NULL;
  1321. PWCHAR LocalName = NULL;
  1322. PWCHAR BindingString = NULL;
  1323. try {
  1324. NTFRSAPI_DBG_PRINT1("Bind Dcpromo: %ws\n", ComputerName);
  1325. //
  1326. // Return value
  1327. //
  1328. *OutHandle = NULL;
  1329. //
  1330. // If needed, get computer name
  1331. //
  1332. if (ComputerName == NULL) {
  1333. ComputerLen = MAX_COMPUTERNAME_LENGTH + 2;
  1334. LocalName = NtFrsApi_Alloc(ComputerLen * sizeof(WCHAR));
  1335. if (!GetComputerName(LocalName, &ComputerLen)) {
  1336. WStatus = GetLastError();
  1337. NTFRSAPI_DBG_PRINT1("Bind Dcpromo: GetComputerName(); %d\n", WStatus);
  1338. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1339. }
  1340. ComputerName = LocalName;
  1341. }
  1342. //
  1343. // Create a binding string to NtFrs on some machine. Trim leading \\
  1344. //
  1345. FRS_TRIM_LEADING_2SLASH(ComputerName);
  1346. NTFRSAPI_DBG_PRINT1("Bind Dcpromo: compose to %ws\n", ComputerName);
  1347. //
  1348. // DOC: Why are named pipes used here but tcp/ip used everywhere else?
  1349. //
  1350. WStatus = RpcStringBindingCompose(NULL, PROTSEQ_NAMED_PIPE, ComputerName,
  1351. NULL, NULL, &BindingString);
  1352. NTFRSAPI_DBG_PRINT2("Bind Dcpromo: compose done to %ws; %d\n", ComputerName, WStatus);
  1353. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1354. //
  1355. // Store the binding in the handle
  1356. //
  1357. WStatus = RpcBindingFromStringBinding(BindingString, &Handle);
  1358. if (!WIN_SUCCESS(WStatus)) {
  1359. NTFRSAPI_DBG_PRINT2("Bind Dcpromo: RpcBindingFromStringBinding(%ws); %d\n",
  1360. ComputerName, WStatus);
  1361. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1362. }
  1363. //
  1364. // Resolve the binding to the dynamic endpoint
  1365. //
  1366. NTFRSAPI_DBG_PRINT1("Bind Dcpromo: resolve to %ws\n", ComputerName);
  1367. WStatus = RpcEpResolveBinding(Handle, NtFrsApi_ClientIfHandle);
  1368. NTFRSAPI_DBG_PRINT2("Bind Dcpromo: resolve done to %ws; %d\n", ComputerName, WStatus);
  1369. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1370. //
  1371. // Set authentication info
  1372. //
  1373. NTFRSAPI_DBG_PRINT1("Bind Dcpromo: set auth to %ws\n", ComputerName);
  1374. WStatus = RpcBindingSetAuthInfo(Handle,
  1375. NULL,
  1376. RPC_C_AUTHN_LEVEL_NONE,
  1377. RPC_C_AUTHN_NONE,
  1378. NULL,
  1379. RPC_C_AUTHZ_NONE);
  1380. NTFRSAPI_DBG_PRINT2("Bind Dcpromo: set auth done to %ws; %d\n",
  1381. ComputerName, WStatus);
  1382. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, CLEANUP);
  1383. //
  1384. // SUCCESS
  1385. //
  1386. *OutHandle = Handle;
  1387. Handle = NULL;
  1388. WStatus = ERROR_SUCCESS;
  1389. CLEANUP:;
  1390. } except (EXCEPTION_EXECUTE_HANDLER) {
  1391. //
  1392. // Exception (may be RPC)
  1393. //
  1394. GET_EXCEPTION_CODE(WStatus);
  1395. }
  1396. //
  1397. // Clean up any handles, events, memory, ...
  1398. //
  1399. try {
  1400. if (LocalName) {
  1401. FREE(LocalName);
  1402. }
  1403. if (BindingString) {
  1404. WStatus1 = RpcStringFreeW(&BindingString);
  1405. NtFrsApiCheckRpcError(WStatus1, "RpcStringFreeW");
  1406. }
  1407. if (Handle) {
  1408. WStatus1 = RpcBindingFree(&Handle);
  1409. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  1410. }
  1411. } except (EXCEPTION_EXECUTE_HANDLER) {
  1412. //
  1413. // Exception (may be RPC)
  1414. //
  1415. GET_EXCEPTION_CODE(WStatus);
  1416. }
  1417. NTFRSAPI_DBG_PRINT1("Bind Dcpromo Done: %d\n", WStatus);
  1418. return WStatus;
  1419. }
  1420. DWORD
  1421. NtFrsApi_GetServiceHandle(
  1422. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1423. OUT SC_HANDLE *ServiceHandle
  1424. )
  1425. /*++
  1426. Routine Description:
  1427. Open a service on a machine.
  1428. Arguments:
  1429. ServiceHandle - Openned handle to ServiceName
  1430. Return Value:
  1431. Win32 Status
  1432. --*/
  1433. {
  1434. #undef NTFRSAPI_MODULE
  1435. #define NTFRSAPI_MODULE "NtFrsApi_GetServiceHandle:"
  1436. DWORD WStatus;
  1437. SC_HANDLE SCMHandle;
  1438. //
  1439. // Contact the SC manager.
  1440. //
  1441. SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1442. if (!HANDLE_IS_VALID(SCMHandle)) {
  1443. WStatus = GetLastError();
  1444. NtFrsApi_CallBackOnWStatus(ErrorCallBack, L"Service Controller", WStatus);
  1445. return WStatus;
  1446. }
  1447. //
  1448. // Contact the NtFrs service.
  1449. //
  1450. *ServiceHandle = OpenService(SCMHandle,
  1451. SERVICE_NAME,
  1452. SERVICE_INTERROGATE |
  1453. SERVICE_PAUSE_CONTINUE |
  1454. SERVICE_QUERY_STATUS |
  1455. SERVICE_QUERY_CONFIG |
  1456. SERVICE_START |
  1457. SERVICE_STOP |
  1458. SERVICE_CHANGE_CONFIG);
  1459. if (!HANDLE_IS_VALID(*ServiceHandle)) {
  1460. WStatus = GetLastError();
  1461. NtFrsApi_CallBackOnWStatus(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus);
  1462. } else {
  1463. WStatus = ERROR_SUCCESS;
  1464. }
  1465. CloseServiceHandle(SCMHandle);
  1466. return WStatus;
  1467. }
  1468. #define MAX_WAIT_HINT (120 * 1000) // 120 seconds
  1469. DWORD
  1470. NtFrsApi_WaitForService(
  1471. IN SC_HANDLE ServiceHandle,
  1472. IN DWORD WaitHint,
  1473. IN DWORD PendingState,
  1474. IN DWORD FinalState
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. Wait for the indicated service to transition from PendingState
  1479. to State. The service is polled once a second for up to WaitHint
  1480. seconds (WaitHint is in milliseconds). The maximum WaitHint is
  1481. 120 seconds.
  1482. Arguments:
  1483. ServiceHandle - indicates the service.
  1484. WaitHint - From the service status (in milliseconds)
  1485. PendingState - Expected pending state (E.g., SERVICE_START_PENDING)
  1486. FinalState - Expected final state (E.g., SERVICE_RUNNING)
  1487. Return Value:
  1488. Win32 Status
  1489. --*/
  1490. {
  1491. #undef NTFRSAPI_MODULE
  1492. #define NTFRSAPI_MODULE "NtFrsApi_WaitForService:"
  1493. DWORD WStatus;
  1494. SERVICE_STATUS ServiceStatus;
  1495. //
  1496. // Don't wait too long; dcpromo is an interactive app
  1497. //
  1498. if (WaitHint > MAX_WAIT_HINT || !WaitHint) {
  1499. WaitHint = MAX_WAIT_HINT;
  1500. }
  1501. //
  1502. // Get the service's status
  1503. //
  1504. again:
  1505. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  1506. return GetLastError();
  1507. }
  1508. //
  1509. // Done
  1510. //
  1511. if (ServiceStatus.dwCurrentState == FinalState) {
  1512. return ERROR_SUCCESS;
  1513. }
  1514. //
  1515. // Not in pending state; error
  1516. //
  1517. if (ServiceStatus.dwCurrentState != PendingState) {
  1518. return ERROR_OPERATION_ABORTED;
  1519. }
  1520. //
  1521. // Can't wait any longer
  1522. //
  1523. if (WaitHint < 1000) {
  1524. return ERROR_OPERATION_ABORTED;
  1525. }
  1526. //
  1527. // Wait a second
  1528. //
  1529. NTFRSAPI_DBG_PRINT0("Waiting for service.\n");
  1530. Sleep(1000);
  1531. WaitHint -= 1000;
  1532. //
  1533. // Try again
  1534. //
  1535. goto again;
  1536. }
  1537. DWORD
  1538. NtFrsApi_StopService(
  1539. IN SC_HANDLE ServiceHandle,
  1540. OUT LPSERVICE_STATUS ServiceStatus
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. Stop the FRS service.
  1545. Arguments:
  1546. ServiceHandle - An open handle to the service controller.
  1547. ServiceStatus - ptr to struct for returned service status.
  1548. Return Value:
  1549. Win32 Status
  1550. --*/
  1551. {
  1552. #undef NTFRSAPI_MODULE
  1553. #define NTFRSAPI_MODULE "NtFrsApi_StopService:"
  1554. DWORD WStatus;
  1555. //
  1556. // Stop the FRS service.
  1557. // Double stop used to deal with shutdown hang.
  1558. //
  1559. if (!ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus)) {
  1560. WStatus = GetLastError();
  1561. if (WStatus == ERROR_SERVICE_REQUEST_TIMEOUT) {
  1562. WStatus = ERROR_SUCCESS;
  1563. if (!ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus)) {
  1564. WStatus = GetLastError();
  1565. if (WStatus == ERROR_SERVICE_NOT_ACTIVE) {
  1566. WStatus = ERROR_SUCCESS;
  1567. }
  1568. }
  1569. }
  1570. }
  1571. //
  1572. // Wait for the stop to finish.
  1573. //
  1574. WStatus = NtFrsApi_WaitForService(ServiceHandle,
  1575. NtFrsApi_ServiceWaitHint,
  1576. SERVICE_STOP_PENDING,
  1577. SERVICE_STOPPED);
  1578. if (!WIN_SUCCESS(WStatus)) {
  1579. WStatus = FRS_ERR_STOPPING_SERVICE;
  1580. }
  1581. return WStatus;
  1582. }
  1583. PWCHAR
  1584. WINAPI
  1585. NtFrsApi_Cats(
  1586. IN PWCHAR Name1, OPTIONAL
  1587. IN PWCHAR Name2, OPTIONAL
  1588. IN PWCHAR Name3 OPTIONAL
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. Arguments:
  1593. Return Value:
  1594. --*/
  1595. {
  1596. #undef NTFRSAPI_MODULE
  1597. #define NTFRSAPI_MODULE "NtFrsApi_Cats:"
  1598. DWORD FinalSize;
  1599. PWCHAR FinalMsg;
  1600. //
  1601. // sizeof(Names) + sizeof(terminating NULL)
  1602. //
  1603. FinalSize = (((Name1) ? wcslen(Name1) : 0) +
  1604. ((Name2) ? wcslen(Name2) : 0) +
  1605. ((Name3) ? wcslen(Name3) : 0) +
  1606. 1) * sizeof(WCHAR);
  1607. //
  1608. // Nothing but the terminating UNICODE NULL; ignore
  1609. //
  1610. if (FinalSize <= sizeof(WCHAR)) {
  1611. return NULL;
  1612. }
  1613. //
  1614. // Allocate string and concatenate
  1615. //
  1616. FinalMsg = NtFrsApi_Alloc(FinalSize);
  1617. FinalMsg[0] = L'\0';
  1618. if (Name1) {
  1619. wcscat(FinalMsg, Name1);
  1620. }
  1621. if (Name2) {
  1622. wcscat(FinalMsg, Name2);
  1623. }
  1624. if (Name3) {
  1625. wcscat(FinalMsg, Name3);
  1626. }
  1627. return (FinalMsg);
  1628. }
  1629. DWORD
  1630. WINAPI
  1631. NtFrsApiOpenKeyEx(
  1632. IN PCHAR NtFrsApiModule,
  1633. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1634. IN PWCHAR KeyPath,
  1635. IN DWORD KeyAccess,
  1636. OUT HKEY *OutHKey
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. Open KeyPath.
  1641. Arguments:
  1642. NtFrsApiModule - String to identify caller
  1643. ErrorCallBack - Ignored if NULL
  1644. KeyPath - Path of registry key (HKEY_LOCAL_MACHINE)
  1645. KeyAccess - for RegOpenKeyEx()
  1646. OutHKey - From RegOpenKeyEx()
  1647. Return Value:
  1648. Win32 Status
  1649. --*/
  1650. {
  1651. #undef NTFRSAPI_MODULE
  1652. #define NTFRSAPI_MODULE "NtFrsApiOpenKeyEx:"
  1653. DWORD WStatus;
  1654. //
  1655. // Open KeyPath
  1656. //
  1657. *OutHKey = 0;
  1658. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyPath, 0, KeyAccess, OutHKey);
  1659. //
  1660. // Report error
  1661. //
  1662. if (!WIN_SUCCESS(WStatus)) {
  1663. NtFrsApi_CallBackOnWStatus(ErrorCallBack, KeyPath, WStatus);
  1664. NTFRSAPI_DBG_PRINT3("%s RegOpenKeyEx(%ws); %d\n",
  1665. NtFrsApiModule, KeyPath, WStatus);
  1666. }
  1667. return WStatus;
  1668. }
  1669. DWORD
  1670. WINAPI
  1671. NtFrsApiCreateKey(
  1672. IN PCHAR NtFrsApiModule,
  1673. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1674. IN PWCHAR KeyPath,
  1675. IN HKEY HKey,
  1676. IN PWCHAR KeyName,
  1677. OUT HKEY *OutHKey
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. Create KeyPath.
  1682. Arguments:
  1683. NtFrsApiModule - String to identify caller
  1684. ErrorCallBack - Ignored if NULL
  1685. KeyPath - Path of registry key (HKEY_LOCAL_MACHINE)
  1686. KeyAccess - for RegCreateKey()
  1687. OutHKey - From RegCreateKey()
  1688. Return Value:
  1689. Win32 Status
  1690. --*/
  1691. {
  1692. #undef NTFRSAPI_MODULE
  1693. #define NTFRSAPI_MODULE "NtFrsApiCreateKey:"
  1694. DWORD WStatus;
  1695. PWCHAR ObjectName;
  1696. //
  1697. // Open KeyPath
  1698. //
  1699. *OutHKey = 0;
  1700. WStatus = RegCreateKey(HKey, KeyName, OutHKey);
  1701. //
  1702. // Report error
  1703. //
  1704. if (!WIN_SUCCESS(WStatus)) {
  1705. if (KeyPath) {
  1706. ObjectName = NtFrsApi_Cats(KeyPath, L"\\", KeyName);
  1707. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  1708. NTFRSAPI_DBG_PRINT3("%s RegCreateKey(%ws); %d\n",
  1709. NtFrsApiModule, ObjectName, WStatus);
  1710. FREE(ObjectName);
  1711. } else {
  1712. NtFrsApi_CallBackOnWStatus(ErrorCallBack, KeyName, WStatus);
  1713. NTFRSAPI_DBG_PRINT3("%s RegCreateKey(%ws); %d\n",
  1714. NtFrsApiModule, KeyName, WStatus);
  1715. }
  1716. }
  1717. return WStatus;
  1718. }
  1719. DWORD
  1720. WINAPI
  1721. NtFrsApiSetValueEx(
  1722. IN PCHAR NtFrsApiModule,
  1723. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1724. IN PWCHAR KeyPath,
  1725. IN HKEY HKey,
  1726. IN PWCHAR ValueName,
  1727. IN DWORD RegType,
  1728. IN PCHAR RegValue,
  1729. IN DWORD RegSize
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. Set value
  1734. Arguments:
  1735. NtFrsApiModule - String to identify caller
  1736. ErrorCallBack - Ignored if NULL
  1737. KeyPath - Path of registry key (HKEY_LOCAL_MACHINE)
  1738. HKey - For call to RegSetValueEx()
  1739. ValueName - For Call to RegSetValueEx()
  1740. RegType - For Call to RegSetValueEx()
  1741. RegValue - For Call to RegSetValueEx()
  1742. RegSize - For Call to RegSetValueEx()
  1743. Return Value:
  1744. Win32 Status
  1745. --*/
  1746. {
  1747. #undef NTFRSAPI_MODULE
  1748. #define NTFRSAPI_MODULE "NtFrsApiSetValueEx:"
  1749. DWORD WStatus;
  1750. PWCHAR ObjectName;
  1751. //
  1752. // Set the value
  1753. //
  1754. WStatus = RegSetValueEx(HKey, ValueName, 0, RegType, RegValue, RegSize);
  1755. //
  1756. // Report error
  1757. //
  1758. if (!WIN_SUCCESS(WStatus)) {
  1759. if (KeyPath) {
  1760. ObjectName = NtFrsApi_Cats(KeyPath, L"->", ValueName);
  1761. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  1762. NTFRSAPI_DBG_PRINT3("%s RegSetValueEx(%ws); %d\n",
  1763. NtFrsApiModule, ObjectName, WStatus);
  1764. FREE(ObjectName);
  1765. } else {
  1766. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ValueName, WStatus);
  1767. NTFRSAPI_DBG_PRINT3("%s RegSetValueEx(%ws); %d\n",
  1768. NtFrsApiModule, ValueName, WStatus);
  1769. }
  1770. }
  1771. return WStatus;
  1772. }
  1773. DWORD
  1774. WINAPI
  1775. NtFrsApiDeleteValue(
  1776. IN PCHAR NtFrsApiModule,
  1777. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1778. IN PWCHAR KeyPath,
  1779. IN HKEY HKey,
  1780. IN PWCHAR ValueName
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. Delete value.
  1785. Arguments:
  1786. NtFrsApiModule - String to identify caller
  1787. ErrorCallBack - Ignored if NULL
  1788. KeyPath - Path of registry key (HKEY_LOCAL_MACHINE)
  1789. HKey - For call to RegDeleteValue()
  1790. ValueName - For Call to RegDeleteValue()
  1791. Return Value:
  1792. Win32 Status
  1793. --*/
  1794. {
  1795. #undef NTFRSAPI_MODULE
  1796. #define NTFRSAPI_MODULE "NtFrsApiDeleteValue:"
  1797. DWORD WStatus;
  1798. PWCHAR ObjectName;
  1799. //
  1800. // Set the value
  1801. //
  1802. WStatus = RegDeleteValue(HKey, ValueName);
  1803. //
  1804. // Report error
  1805. //
  1806. if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_FILE_NOT_FOUND) {
  1807. if (KeyPath) {
  1808. ObjectName = NtFrsApi_Cats(KeyPath, L"->", ValueName);
  1809. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  1810. NTFRSAPI_DBG_PRINT3("%s RegDeleteValue(%ws); %d\n",
  1811. NtFrsApiModule, ObjectName, WStatus);
  1812. FREE(ObjectName);
  1813. } else {
  1814. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ValueName, WStatus);
  1815. NTFRSAPI_DBG_PRINT3("%s RegDeleteValue(%ws); %d\n",
  1816. NtFrsApiModule, ValueName, WStatus);
  1817. }
  1818. }
  1819. return WStatus;
  1820. }
  1821. DWORD
  1822. WINAPI
  1823. NtFrsApiDeleteKey(
  1824. IN PCHAR NtFrsApiModule,
  1825. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1826. IN PWCHAR KeyPath,
  1827. IN HKEY HKey,
  1828. IN PWCHAR KeyName
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. Delete key.
  1833. Arguments:
  1834. NtFrsApiModule - String to identify caller
  1835. ErrorCallBack - Ignored if NULL
  1836. KeyPath - Path of registry key (HKEY_LOCAL_MACHINE)
  1837. HKey - For call to RegDeleteKey()
  1838. KeyName - For Call to RegDeleteKey()
  1839. Return Value:
  1840. Win32 Status
  1841. --*/
  1842. {
  1843. #undef NTFRSAPI_MODULE
  1844. #define NTFRSAPI_MODULE "NtFrsApiDeleteKey:"
  1845. DWORD WStatus;
  1846. PWCHAR ObjectName;
  1847. //
  1848. // Set the value
  1849. //
  1850. WStatus = RegDeleteKey(HKey, KeyName);
  1851. //
  1852. // Report error
  1853. //
  1854. if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_FILE_NOT_FOUND) {
  1855. if (KeyPath) {
  1856. ObjectName = NtFrsApi_Cats(KeyPath, L"\\", KeyName);
  1857. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  1858. NTFRSAPI_DBG_PRINT3("%s RegDeleteKey(%ws); %d\n",
  1859. NtFrsApiModule, ObjectName, WStatus);
  1860. FREE(ObjectName);
  1861. } else {
  1862. NtFrsApi_CallBackOnWStatus(ErrorCallBack, KeyName, WStatus);
  1863. NTFRSAPI_DBG_PRINT3("%s RegDeleteKey(%ws); %d\n",
  1864. NtFrsApiModule, KeyName, WStatus);
  1865. }
  1866. }
  1867. return WStatus;
  1868. }
  1869. DWORD
  1870. WINAPI
  1871. NtFrsApi_Prepare(
  1872. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  1873. IN BOOL IsDemote
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. The NtFrs service seeds the system volume during the promotion
  1878. of a server to a Domain Controller (DC) and stops replicating
  1879. the system volumes when a DC is demoted to a member server.
  1880. Replication is stopped by tombstoning the system volume's
  1881. replica set.
  1882. This function prepares the NtFrs service on this machine by
  1883. stopping the service, deleting old state in the registry,
  1884. and restarting the service. The service's current state is
  1885. retained and restored if the promotion or demotion are
  1886. aborted.
  1887. Arguments:
  1888. IsDemote - TRUE: prepare for demotion
  1889. FALSE: prepare for promotion
  1890. Return Value:
  1891. Win32 Status
  1892. --*/
  1893. {
  1894. #undef NTFRSAPI_MODULE
  1895. #define NTFRSAPI_MODULE "NtFrsApi_Prepare:"
  1896. DWORD WStatus;
  1897. SERVICE_STATUS ServiceStatus;
  1898. DWORD ValueLen;
  1899. DWORD ValueType;
  1900. DWORD SysvolReady;
  1901. PWCHAR ObjectName = NULL;
  1902. HKEY HKey = 0;
  1903. HKEY HNetKey = 0;
  1904. SC_HANDLE ServiceHandle = NULL;
  1905. WCHAR KeyBuf[MAX_PATH + 1];
  1906. try {
  1907. //
  1908. // Acquire global lock within a try-finally
  1909. //
  1910. EnterCriticalSection(&NtFrsApi_GlobalLock);
  1911. NTFRSAPI_DBG_PRINT0("Prepare:\n");
  1912. //
  1913. // This function is designed to be called once!
  1914. //
  1915. if (NtFrsApi_State != NTFRSAPI_LOADED) {
  1916. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  1917. goto done;
  1918. }
  1919. NtFrsApi_State = NTFRSAPI_PREPARING;
  1920. //
  1921. // Stop the service, delete old state from the registry,
  1922. // and restart the service
  1923. //
  1924. try {
  1925. //
  1926. // Set the RPC cancel timeout to "now"
  1927. //
  1928. WStatus = RpcMgmtSetCancelTimeout(0);
  1929. if (!WIN_SUCCESS(WStatus)) {
  1930. NTFRSAPI_DBG_PRINT1("Prepare: RpcMgmtSetCancelTimeout(); %d\n", WStatus);
  1931. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1932. }
  1933. //
  1934. // Open the ntfrs parameters\sysvol section in the registry
  1935. //
  1936. NTFRSAPI_DBG_PRINT0("Prepare: Global registry options\n");
  1937. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  1938. ErrorCallBack,
  1939. FRS_SYSVOL_SECTION,
  1940. KEY_ALL_ACCESS,
  1941. &HKey);
  1942. if (!WIN_SUCCESS(WStatus)) {
  1943. goto cleanup;
  1944. }
  1945. //
  1946. // Insure access to the netlogon\parameters key
  1947. //
  1948. NTFRSAPI_DBG_PRINT0("Prepare: Netlogon registry\n");
  1949. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  1950. ErrorCallBack,
  1951. NETLOGON_SECTION,
  1952. KEY_ALL_ACCESS,
  1953. &HNetKey);
  1954. if (!WIN_SUCCESS(WStatus)) {
  1955. goto cleanup;
  1956. }
  1957. //
  1958. // Tell NetLogon to stop sharing the sysvol
  1959. // NtFrs will reset the value if a seeded sysvol is
  1960. // detected at startup.
  1961. //
  1962. SysvolReady = 0;
  1963. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  1964. ErrorCallBack,
  1965. NETLOGON_SECTION,
  1966. HNetKey,
  1967. SYSVOL_READY,
  1968. REG_DWORD,
  1969. (PCHAR)&SysvolReady,
  1970. sizeof(DWORD));
  1971. if (!WIN_SUCCESS(WStatus)) {
  1972. goto cleanup;
  1973. }
  1974. //
  1975. // Open the service
  1976. //
  1977. NTFRSAPI_DBG_PRINT0("Prepare: Service\n");
  1978. WStatus = NtFrsApi_GetServiceHandle(ErrorCallBack, &ServiceHandle);
  1979. if (!WIN_SUCCESS(WStatus)) {
  1980. goto cleanup;
  1981. }
  1982. //
  1983. // Get the service's status
  1984. //
  1985. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  1986. WStatus = GetLastError();
  1987. NTFRSAPI_DBG_PRINT1("Prepare: QueryServiceStatus(); %d\n", WStatus);
  1988. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  1989. }
  1990. //
  1991. // Remember the current state
  1992. //
  1993. NtFrsApi_ServiceState = ServiceStatus.dwCurrentState;
  1994. NtFrsApi_ServiceWaitHint = ServiceStatus.dwWaitHint;
  1995. NtFrsApi_State = NTFRSAPI_PREPARED_SERVICE;
  1996. //
  1997. // Stop the service
  1998. //
  1999. if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  2000. WStatus = NtFrsApi_StopService(ServiceHandle, &ServiceStatus);
  2001. if (!WIN_SUCCESS(WStatus)) {
  2002. goto cleanup;
  2003. }
  2004. }
  2005. //
  2006. // Delete old state from the registry
  2007. //
  2008. //
  2009. // Open the ntfrs parameters\sysvol section in the registry
  2010. //
  2011. NTFRSAPI_DBG_PRINT0("Prepare: Registry\n");
  2012. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  2013. ErrorCallBack,
  2014. FRS_SYSVOL_SECTION,
  2015. KEY_ALL_ACCESS,
  2016. &HKey);
  2017. if (!WIN_SUCCESS(WStatus)) {
  2018. goto cleanup;
  2019. }
  2020. //
  2021. // Delete the value that indicates the sysvol subkeys are valid
  2022. //
  2023. WStatus = NtFrsApiDeleteValue(NTFRSAPI_MODULE,
  2024. ErrorCallBack,
  2025. FRS_SYSVOL_SECTION,
  2026. HKey,
  2027. SYSVOL_INFO_IS_COMMITTED);
  2028. if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_FILE_NOT_FOUND) {
  2029. goto cleanup;
  2030. }
  2031. //
  2032. // Delete the subkeys
  2033. //
  2034. do {
  2035. WStatus = RegEnumKey(HKey, 0, KeyBuf, MAX_PATH + 1);
  2036. if (WIN_SUCCESS(WStatus)) {
  2037. WStatus = NtFrsApiDeleteKey(NTFRSAPI_MODULE,
  2038. ErrorCallBack,
  2039. FRS_SYSVOL_SECTION,
  2040. HKey,
  2041. KeyBuf);
  2042. if (!WIN_SUCCESS(WStatus)) {
  2043. goto cleanup;
  2044. }
  2045. }
  2046. } while (WIN_SUCCESS(WStatus));
  2047. if (WStatus != ERROR_NO_MORE_ITEMS) {
  2048. NTFRSAPI_DBG_PRINT2("Prepare: RegEnumKey(%ws); %d\n",
  2049. FRS_SYSVOL_SECTION, WStatus);
  2050. CLEANUP_CB(ErrorCallBack, FRS_SYSVOL_SECTION, WStatus, cleanup);
  2051. }
  2052. //
  2053. // Restart the service
  2054. //
  2055. NTFRSAPI_DBG_PRINT0("Prepare: Restart service\n");
  2056. if (!StartService(ServiceHandle, 0, NULL)) {
  2057. WStatus = GetLastError();
  2058. NTFRSAPI_DBG_PRINT2("Prepare: StartService(%ws); %d\n",
  2059. NtFrsApi_ServiceLongName, WStatus);
  2060. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  2061. }
  2062. //
  2063. // Wait for the service to start
  2064. //
  2065. WStatus = NtFrsApi_WaitForService(ServiceHandle,
  2066. NtFrsApi_ServiceWaitHint,
  2067. SERVICE_START_PENDING,
  2068. SERVICE_RUNNING);
  2069. if (!WIN_SUCCESS(WStatus)) {
  2070. WStatus = FRS_ERR_STARTING_SERVICE;
  2071. goto cleanup;
  2072. }
  2073. //
  2074. // Success
  2075. //
  2076. WStatus = ERROR_SUCCESS;
  2077. NtFrsApi_State = NTFRSAPI_PREPARED;
  2078. cleanup:;
  2079. } except (EXCEPTION_EXECUTE_HANDLER) {
  2080. GET_EXCEPTION_CODE(WStatus);
  2081. }
  2082. //
  2083. // Clean up any handles, events, memory, ...
  2084. //
  2085. try {
  2086. if (ServiceHandle) {
  2087. CloseServiceHandle(ServiceHandle);
  2088. }
  2089. if (HANDLE_IS_VALID(HKey)) {
  2090. RegCloseKey(HKey);
  2091. }
  2092. if (HANDLE_IS_VALID(HNetKey)) {
  2093. RegCloseKey(HNetKey);
  2094. }
  2095. FREE(ObjectName);
  2096. } except (EXCEPTION_EXECUTE_HANDLER) {
  2097. GET_EXCEPTION_CODE(WStatus);
  2098. }
  2099. done:;
  2100. } finally {
  2101. //
  2102. // Release locks
  2103. //
  2104. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  2105. if (AbnormalTermination()) {
  2106. WStatus = FRS_ERR_INTERNAL_API;
  2107. }
  2108. }
  2109. NTFRSAPI_DBG_PRINT1("Prepare done: %d\n", WStatus);
  2110. return WStatus;
  2111. }
  2112. DWORD
  2113. WINAPI
  2114. NtFrsApi_PrepareForPromotionW(
  2115. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  2116. )
  2117. /*++
  2118. Routine Description:
  2119. The NtFrs service seeds the system volume during the promotion
  2120. of a server to a Domain Controller (DC). The files and directories
  2121. for the system volume come from the same machine that is supplying
  2122. the initial Directory Service (DS).
  2123. This function prepares the NtFrs service on this machine for
  2124. promotion by stopping the service, deleting old promotion
  2125. state in the registry, and restarting the service.
  2126. This function is not idempotent and isn't MT safe.
  2127. Arguments:
  2128. None.
  2129. Return Value:
  2130. Win32 Status
  2131. --*/
  2132. {
  2133. #undef NTFRSAPI_MODULE
  2134. #define NTFRSAPI_MODULE "NtFrsApi_PrepareForPromotionW:"
  2135. DWORD WStatus;
  2136. NTFRSAPI_DBG_PREPARE();
  2137. NTFRSAPI_DBG_PRINT0("\n");
  2138. NTFRSAPI_DBG_PRINT0("=============== Promotion Start:\n");
  2139. NTFRSAPI_DBG_PRINT0("\n");
  2140. NTFRSAPI_DBG_PRINT0("Prepare promotion:\n");
  2141. WStatus = NtFrsApi_Prepare(ErrorCallBack, FALSE);
  2142. NTFRSAPI_DBG_PRINT1("Prepare promotion done: %d\n", WStatus);
  2143. return WStatus;
  2144. }
  2145. PVOID *
  2146. DsDeleteFindValues(
  2147. IN PLDAP Ldap,
  2148. IN PLDAPMessage LdapEntry,
  2149. IN PWCHAR DesiredAttr
  2150. )
  2151. /*++
  2152. Routine Description:
  2153. Return the DS values for one attribute in an entry.
  2154. Arguments:
  2155. Ldap - An open, bound ldap port.
  2156. LdapEntry - An ldap entry returned by ldap_search_s()
  2157. DesiredAttr - Return values for this attribute.
  2158. Return Value:
  2159. An array of char pointers that represents the values for the attribute.
  2160. The caller must free the array with LDAP_FREE_VALUES().
  2161. NULL if unsuccessful.
  2162. --*/
  2163. {
  2164. #undef NTFRSAPI_MODULE
  2165. #define NTFRSAPI_MODULE "DsDeleteFindValues:"
  2166. PWCHAR Attr; // Retrieved from an ldap entry
  2167. BerElement *Ber; // Needed for scanning attributes
  2168. //
  2169. // Search the entry for the desired attribute
  2170. //
  2171. for (Attr = ldap_first_attribute(Ldap, LdapEntry, &Ber);
  2172. Attr != NULL;
  2173. Attr = ldap_next_attribute(Ldap, LdapEntry, Ber)) {
  2174. if (WSTR_EQ(DesiredAttr, Attr)) {
  2175. //
  2176. // Return the values for DesiredAttr
  2177. //
  2178. return ldap_get_values(Ldap, LdapEntry, Attr);
  2179. }
  2180. }
  2181. return NULL;
  2182. }
  2183. VOID
  2184. WINAPI
  2185. DsDeletePrepare(
  2186. IN SEC_WINNT_AUTH_IDENTITY *Credentials OPTIONAL
  2187. )
  2188. /*++
  2189. Routine Description:
  2190. Called from NtFrsApi_PrepareForDemotionW().
  2191. Squirrel away an ldap binding to another DS. After the
  2192. demotion is committed, the settings, set, member, subscriptions,
  2193. and subscriber objects will be deleted.
  2194. Arguments:
  2195. Credentials -- Credentionals to use in ldap binding call, if supplied.
  2196. Return Value:
  2197. None.
  2198. --*/
  2199. {
  2200. #undef NTFRSAPI_MODULE
  2201. #define NTFRSAPI_MODULE "DsDeletePrepare:"
  2202. DWORD WStatus;
  2203. DWORD Idx;
  2204. DWORD LStatus = LDAP_SUCCESS;
  2205. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  2206. PLDAPMessage LdapEntry;
  2207. PLDAPMessage LdapMsg = NULL;
  2208. PWCHAR *LdapValues = NULL;
  2209. PWCHAR LdapValue;
  2210. PWCHAR Attrs[3];
  2211. PWCHAR DomainName;
  2212. PWCHAR DomainControllerName = NULL;
  2213. PWCHAR DomainControllerAddress = NULL;
  2214. struct l_timeval Timeout;
  2215. DWORD InfoFlags;
  2216. CHAR FlagBuffer[220];
  2217. ULONG ulOptions;
  2218. DsDeleteLdap = NULL;
  2219. //
  2220. // computer name
  2221. //
  2222. Idx = MAX_COMPUTERNAME_LENGTH + 2;
  2223. if (!GetComputerNameEx(ComputerNameNetBIOS, DsDeleteComputerName, &Idx)) {
  2224. NTFRSAPI_DBG_PRINT1("ERROR - Can't get computer name; %d\n", GetLastError());
  2225. goto CLEANUP;
  2226. }
  2227. NTFRSAPI_DBG_PRINT1("Computer name is %ws\n", DsDeleteComputerName);
  2228. //
  2229. // domain name
  2230. //
  2231. Idx = MAX_PATH + 2;
  2232. if (!GetComputerNameEx(ComputerNameDnsDomain, DsDeleteDomainDnsName, &Idx)) {
  2233. NTFRSAPI_DBG_PRINT1("ERROR - Can't get domain name; %d\n", GetLastError());
  2234. goto CLEANUP;
  2235. }
  2236. NTFRSAPI_DBG_PRINT1("Domain name is %ws\n", DsDeleteDomainDnsName);
  2237. //
  2238. // Find any DC in our hierarchy of DCs
  2239. //
  2240. DomainName = DsDeleteDomainDnsName;
  2241. FIND_DC:
  2242. NTFRSAPI_DBG_PRINT1("Trying domain name is %ws\n", DomainName);
  2243. WStatus = DsGetDcName(NULL, // Computer to remote to
  2244. DomainName,
  2245. NULL, // Domain Guid
  2246. NULL, // Site Guid
  2247. DS_DIRECTORY_SERVICE_REQUIRED |
  2248. DS_WRITABLE_REQUIRED |
  2249. DS_BACKGROUND_ONLY |
  2250. DS_AVOID_SELF,
  2251. &DcInfo); // Return info
  2252. //
  2253. // Report the error and retry for any DC
  2254. //
  2255. if (!WIN_SUCCESS(WStatus)) {
  2256. DcInfo = NULL;
  2257. NTFRSAPI_DBG_PRINT2("WARN - Could not get DC Info for %ws; WStatus %d\n",
  2258. DomainName, WStatus);
  2259. //
  2260. // Try the parent domain
  2261. //
  2262. while (*DomainName && *DomainName != L'.') {
  2263. ++DomainName;
  2264. }
  2265. if (*DomainName) {
  2266. ++DomainName;
  2267. goto FIND_DC;
  2268. }
  2269. goto CLEANUP;
  2270. }
  2271. NTFRSAPI_DBG_PRINT1("DomainControllerName : %ws\n", DcInfo->DomainControllerName);
  2272. NTFRSAPI_DBG_PRINT1("DomainControllerAddress: %ws\n", DcInfo->DomainControllerAddress);
  2273. NTFRSAPI_DBG_PRINT1("DomainControllerType : %08x\n",DcInfo->DomainControllerAddressType);
  2274. NTFRSAPI_DBG_PRINT1("DomainName : %ws\n", DcInfo->DomainName);
  2275. NTFRSAPI_DBG_PRINT1("DcSiteName : %ws\n", DcInfo->DcSiteName);
  2276. NTFRSAPI_DBG_PRINT1("ClientSiteName : %ws\n", DcInfo->ClientSiteName);
  2277. InfoFlags = DcInfo->Flags;
  2278. FrsFlagsToStr(InfoFlags, NtFrsApi_DsGetDcInfoFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
  2279. NTFRSAPI_DBG_PRINT2("Flags : %08x Flags [%s]\n",InfoFlags, FlagBuffer);
  2280. //
  2281. // Open and bind to the DS
  2282. //
  2283. //
  2284. // if ldap_open is called with a server name the api will call DsGetDcName
  2285. // passing the server name as the domainname parm...bad, because
  2286. // DsGetDcName will make a load of DNS queries based on the server name,
  2287. // it is designed to construct these queries from a domain name...so all
  2288. // these queries will be bogus, meaning they will waste network bandwidth,
  2289. // time to fail, and worst case cause expensive on demand links to come up
  2290. // as referrals/forwarders are contacted to attempt to resolve the bogus
  2291. // names. By setting LDAP_OPT_AREC_EXCLUSIVE to on using ldap_set_option
  2292. // after the ldap_init but before any other operation using the ldap
  2293. // handle from ldap_init, the delayed connection setup will not call
  2294. // DsGetDcName, just gethostbyname, or if an IP is passed, the ldap client
  2295. // will detect that and use the address directly.
  2296. //
  2297. //
  2298. // Trim the leadinf \\ because ldap does not like it.
  2299. //
  2300. // DsDeleteLdap = ldap_open(DcInfo->DomainControllerName, LDAP_PORT);
  2301. ulOptions = PtrToUlong(LDAP_OPT_ON);
  2302. Timeout.tv_sec = NTFRSAPI_LDAP_CONNECT_TIMEOUT;
  2303. Timeout.tv_usec = 0;
  2304. //
  2305. // Try using DomainControllerName first.
  2306. //
  2307. if (DcInfo->DomainControllerName != NULL) {
  2308. DomainControllerName = DcInfo->DomainControllerName;
  2309. FRS_TRIM_LEADING_2SLASH(DomainControllerName);
  2310. DsDeleteLdap = ldap_init(DomainControllerName, LDAP_PORT);
  2311. if (DsDeleteLdap != NULL) {
  2312. ldap_set_option(DsDeleteLdap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  2313. LStatus = ldap_connect(DsDeleteLdap, &Timeout);
  2314. if (LStatus != LDAP_SUCCESS) {
  2315. NTFRSAPI_DBG_PRINT2("ERROR - Connecting to the DS on %ws; %ws)\n",
  2316. DomainControllerName, ldap_err2string(LStatus));
  2317. ldap_unbind_s(DsDeleteLdap);
  2318. DsDeleteLdap = NULL;
  2319. }
  2320. }
  2321. }
  2322. //
  2323. // Try using DomainControllerAddress next.
  2324. //
  2325. if ((DsDeleteLdap == NULL) && (DcInfo->DomainControllerAddress != NULL)) {
  2326. DomainControllerAddress = DcInfo->DomainControllerAddress;
  2327. FRS_TRIM_LEADING_2SLASH(DomainControllerAddress);
  2328. DsDeleteLdap = ldap_init(DomainControllerAddress, LDAP_PORT);
  2329. if (DsDeleteLdap != NULL) {
  2330. ldap_set_option(DsDeleteLdap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  2331. LStatus = ldap_connect(DsDeleteLdap, &Timeout);
  2332. if (LStatus != LDAP_SUCCESS) {
  2333. NTFRSAPI_DBG_PRINT2("ERROR - Connecting to the DS on %ws; %ws)\n",
  2334. DomainControllerAddress, ldap_err2string(LStatus));
  2335. ldap_unbind_s(DsDeleteLdap);
  2336. DsDeleteLdap = NULL;
  2337. }
  2338. }
  2339. }
  2340. //
  2341. // Can not connect to DC. Give up.
  2342. //
  2343. if (DsDeleteLdap == NULL) {
  2344. goto CLEANUP;
  2345. }
  2346. LStatus = ldap_bind_s(DsDeleteLdap, NULL, (PWCHAR) Credentials, LDAP_AUTH_NEGOTIATE);
  2347. if (LStatus != LDAP_SUCCESS) {
  2348. NTFRSAPI_DBG_PRINT2("ERROR - Binding to the DS on %ws; %ws)\n",
  2349. DcInfo->DomainControllerName, ldap_err2string(LStatus));
  2350. ldap_unbind_s(DsDeleteLdap);
  2351. DsDeleteLdap = NULL;
  2352. goto CLEANUP;
  2353. }
  2354. //
  2355. // Fetch the naming contexts
  2356. //
  2357. Attrs[0] = ATTR_NAMING_CONTEXTS;
  2358. Attrs[1] = ATTR_DEFAULT_NAMING_CONTEXT;
  2359. Attrs[2] = NULL;
  2360. LStatus = ldap_search_s(DsDeleteLdap,
  2361. CN_ROOT,
  2362. LDAP_SCOPE_BASE,
  2363. CATEGORY_ANY,
  2364. Attrs,
  2365. 0,
  2366. &LdapMsg);
  2367. if (LStatus != LDAP_SUCCESS) {
  2368. NTFRSAPI_DBG_PRINT2("ERROR - Getting naming contexts from %ws; %ws\n",
  2369. DcInfo->DomainControllerName, ldap_err2string(LStatus));
  2370. goto CLEANUP;
  2371. }
  2372. LdapEntry = ldap_first_entry(DsDeleteLdap, LdapMsg);
  2373. if (!LdapEntry) {
  2374. NTFRSAPI_DBG_PRINT1("ERROR - No naming contexts for %ws\n",
  2375. DcInfo->DomainControllerName);
  2376. goto CLEANUP;
  2377. }
  2378. //
  2379. // ATTR_NAMING_CONTEXTS
  2380. // Configuration, Schema, and ???
  2381. //
  2382. LdapValues = (PWCHAR *)DsDeleteFindValues(DsDeleteLdap,
  2383. LdapEntry,
  2384. ATTR_NAMING_CONTEXTS);
  2385. if (!LdapValues) {
  2386. NTFRSAPI_DBG_PRINT1("ERROR - no values for naming contexts for %ws\n",
  2387. DcInfo->DomainControllerName);
  2388. goto CLEANUP;
  2389. }
  2390. //
  2391. // Now, find the naming context that begins with "cn=configuration"
  2392. //
  2393. Idx = ldap_count_values(LdapValues);
  2394. while (Idx--) {
  2395. if (!LdapValues[Idx]) {
  2396. continue;
  2397. }
  2398. _wcslwr(LdapValues[Idx]);
  2399. LdapValue = wcsstr(LdapValues[Idx], CONFIG_NAMING_CONTEXT);
  2400. if (LdapValue && LdapValue == LdapValues[Idx]) {
  2401. break;
  2402. } else {
  2403. LdapValue = NULL;
  2404. }
  2405. }
  2406. if (!LdapValue) {
  2407. NTFRSAPI_DBG_PRINT1("ERROR - No configuration naming context from %ws\n",
  2408. DcInfo->DomainControllerName);
  2409. goto CLEANUP;
  2410. }
  2411. wcscpy(DsDeleteConfigDn, LdapValue);
  2412. NTFRSAPI_DBG_PRINT1("Configuration naming context is %ws\n", DsDeleteConfigDn);
  2413. ldap_value_free(LdapValues);
  2414. LdapValues = NULL;
  2415. //
  2416. // ATTR_DEFAULT_NAMING_CONTEXT
  2417. //
  2418. LdapValues = (PWCHAR *)DsDeleteFindValues(DsDeleteLdap,
  2419. LdapEntry,
  2420. ATTR_DEFAULT_NAMING_CONTEXT);
  2421. if (!LdapValues || !LdapValues[0]) {
  2422. NTFRSAPI_DBG_PRINT1("ERROR - No values for default naming context from %ws\n",
  2423. DcInfo->DomainControllerName);
  2424. goto CLEANUP;
  2425. }
  2426. wcscpy(DsDeleteDefaultDn, LdapValues[0]);
  2427. NTFRSAPI_DBG_PRINT1("Default naming context is %ws\n", DsDeleteDefaultDn);
  2428. ldap_value_free(LdapValues);
  2429. LdapValues = NULL;
  2430. CLEANUP:
  2431. if (LdapMsg) {
  2432. ldap_msgfree(LdapMsg);
  2433. }
  2434. if (LdapValues) {
  2435. ldap_value_free(LdapValues);
  2436. }
  2437. if (DcInfo) {
  2438. NetApiBufferFree(DcInfo);
  2439. DcInfo = NULL;
  2440. }
  2441. }
  2442. VOID
  2443. WINAPI
  2444. DsDeleteCommit(
  2445. VOID
  2446. )
  2447. /*++
  2448. Routine Description:
  2449. Called from NtFrsApi_CommitDemotionW().
  2450. Use the binding squirreled away by DsDeletePrepare() to attempt
  2451. the deletion of the settings, set, member, subscriptions, and
  2452. subscriber objects.
  2453. Arguments:
  2454. None.
  2455. Return Value:
  2456. None.
  2457. --*/
  2458. {
  2459. #undef NTFRSAPI_MODULE
  2460. #define NTFRSAPI_MODULE "DsDeleteCommit:"
  2461. DWORD Idx;
  2462. DWORD LStatus;
  2463. LONG Count;
  2464. PNTFRSAPI_THREAD Thread;
  2465. PFQDN_CONSTRUCTION_TABLE Entry;
  2466. PWCHAR ArgTable[FQDN_MAX_COUNT];
  2467. WCHAR Dn[MAX_DN];
  2468. //
  2469. // No binding; done
  2470. //
  2471. if (!DsDeleteLdap) {
  2472. goto CLEANUP;
  2473. }
  2474. //
  2475. // For each sysvol
  2476. //
  2477. for (Thread = NtFrsApi_Threads, Idx = 0;
  2478. Thread && Idx < NtFrsApi_NumberOfThreads;
  2479. Thread = Thread->Next, ++Idx) {
  2480. //
  2481. // First make a copy of the standard argument table and then update the
  2482. // entries to point to variable arguments. Most of the standard argument
  2483. // entries point to contstant name strings or to Global Strings.
  2484. //
  2485. CopyMemory(ArgTable, FQDN_StdArgTable, sizeof(ArgTable));
  2486. if (Thread->ReplicaSetName != NULL) {
  2487. ArgTable[FQDN_RepSetName] = Thread->ReplicaSetName;;
  2488. }
  2489. //
  2490. // Loop thru the entries in the FrsDsObjectDeleteTable, build each
  2491. // FQDN string and make the call to delete the object.
  2492. //
  2493. Entry = FrsDsObjectDeleteTable;
  2494. while (Entry->Description != NULL) {
  2495. //
  2496. // Construct the FQDN string for the object.
  2497. //
  2498. Count = _snwprintf(Dn, MAX_DN, Entry->Format,
  2499. ArgTable[Entry->Arg[0]], ArgTable[Entry->Arg[1]],
  2500. ArgTable[Entry->Arg[2]], ArgTable[Entry->Arg[3]],
  2501. ArgTable[Entry->Arg[4]], ArgTable[Entry->Arg[5]],
  2502. ArgTable[Entry->Arg[6]], ArgTable[Entry->Arg[7]]);
  2503. //
  2504. // Delete the object.
  2505. //
  2506. if (Count > 0) {
  2507. NTFRSAPI_DBG_PRINT2("%s: %ws\n", Entry->Description, Dn);
  2508. LStatus = ldap_delete_s(DsDeleteLdap, Dn);
  2509. if (LStatus != LDAP_SUCCESS && LStatus != LDAP_NO_SUCH_OBJECT) {
  2510. NTFRSAPI_DBG_PRINT4("ERROR - Can't delete %s (%ws) for %ws; %ws\n",
  2511. Entry->Description, Dn, ArgTable[FQDN_RepSetName],
  2512. ldap_err2string(LStatus));
  2513. }
  2514. } else {
  2515. NTFRSAPI_DBG_PRINT2("ERROR - Can't construct %s for %ws\n",
  2516. Entry->Description, ArgTable[FQDN_RepSetName]);
  2517. }
  2518. Entry++;
  2519. }
  2520. }
  2521. CLEANUP:
  2522. if (DsDeleteLdap) {
  2523. ldap_unbind_s(DsDeleteLdap);
  2524. DsDeleteLdap = NULL;
  2525. }
  2526. }
  2527. DWORD
  2528. WINAPI
  2529. NtFrsApi_PrepareForDemotionW(
  2530. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  2531. )
  2532. /*++
  2533. Routine Description:
  2534. The NtFrs service replicates the enterprise system volume to all
  2535. Domain Controllers (DCs) and replicates the domain system volume
  2536. to the DCs in a domain until the DC is demoted to a member server.
  2537. Replication is stopped by tombstoning the system volume's replica
  2538. set.
  2539. This function prepares the NtFrs service on this machine for
  2540. demotion by stopping the service, deleting old demotion
  2541. state in the registry, and restarting the service.
  2542. This function is not idempotent and isn't MT safe.
  2543. Arguments:
  2544. None.
  2545. Return Value:
  2546. Win32 Status
  2547. --*/
  2548. {
  2549. #undef NTFRSAPI_MODULE
  2550. #define NTFRSAPI_MODULE "NtFrsApi_PrepareForDemotionW:"
  2551. DWORD WStatus;
  2552. NTFRSAPI_DBG_PREPARE();
  2553. NTFRSAPI_DBG_PRINT0("\n");
  2554. NTFRSAPI_DBG_PRINT0("=============== Demotion Starting: \n");
  2555. NTFRSAPI_DBG_PRINT0("\n");
  2556. NTFRSAPI_DBG_PRINT0("Prepare demotion:\n");
  2557. WStatus = NtFrsApi_Prepare(ErrorCallBack, TRUE);
  2558. NTFRSAPI_DBG_PRINT1("Prepare demotion done: %d\n", WStatus);
  2559. NTFRSAPI_DBG_PRINT0("Prepare delete:\n");
  2560. DsDeletePrepare(NULL);
  2561. NTFRSAPI_DBG_PRINT1("Prepare delete done: %d\n", WStatus);
  2562. return WStatus;
  2563. }
  2564. DWORD
  2565. WINAPI
  2566. NtFrsApi_PrepareForDemotionUsingCredW(
  2567. IN SEC_WINNT_AUTH_IDENTITY *Credentials, OPTIONAL
  2568. IN HANDLE ClientToken,
  2569. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. The NtFrs service replicates the enterprise system volume to all
  2574. Domain Controllers (DCs) and replicates the domain system volume
  2575. to the DCs in a domain until the DC is demoted to a member server.
  2576. Replication is stopped by tombstoning the system volume's replica
  2577. set.
  2578. This function prepares the NtFrs service on this machine for
  2579. demotion by stopping the service, deleting old demotion
  2580. state in the registry, and restarting the service.
  2581. This function is not idempotent and isn't MT safe.
  2582. Arguments:
  2583. Credentials -- Credentionals to use in ldap binding call, if supplied.
  2584. ClientToken -- Impersonation token to use if no Credentials supplied.
  2585. Return Value:
  2586. Win32 Status
  2587. --*/
  2588. {
  2589. #undef NTFRSAPI_MODULE
  2590. #define NTFRSAPI_MODULE "NtFrsApi_PrepareForDemotionUsingCredW:"
  2591. DWORD WStatus;
  2592. NTFRSAPI_DBG_PREPARE();
  2593. NTFRSAPI_DBG_PRINT0("\n");
  2594. NTFRSAPI_DBG_PRINT0("=============== Demotion Starting: \n");
  2595. NTFRSAPI_DBG_PRINT0("\n");
  2596. NTFRSAPI_DBG_PRINT0("Prepare demotion:\n");
  2597. WStatus = NtFrsApi_Prepare(ErrorCallBack, TRUE);
  2598. NTFRSAPI_DBG_PRINT1("Prepare demotion done: %d\n", WStatus);
  2599. NTFRSAPI_DBG_PRINT0("Prepare delete:\n");
  2600. if ((Credentials == NULL) && HANDLE_IS_VALID(ClientToken)) {
  2601. if (ImpersonateLoggedOnUser( ClientToken )) {
  2602. DsDeletePrepare(Credentials);
  2603. NTFRSAPI_DBG_PRINT0("Prepare delete done.\n");
  2604. RevertToSelf();
  2605. } else {
  2606. WStatus = GetLastError();
  2607. NTFRSAPI_DBG_PRINT1("Prepare delete: ImpersonateLoggedOnUser failed: %d\n", WStatus);
  2608. }
  2609. } else {
  2610. DsDeletePrepare(Credentials);
  2611. NTFRSAPI_DBG_PRINT0("Prepare delete done.\n");
  2612. }
  2613. return WStatus;
  2614. }
  2615. DWORD
  2616. WINAPI
  2617. NtFrsApi_Abort(
  2618. VOID
  2619. )
  2620. /*++
  2621. Routine Description:
  2622. The NtFrs service seeds the system volume during the promotion
  2623. of a server to a Domain Controller (DC) and stops replication
  2624. when a server is demoted from a DC by tombstoning the system
  2625. volume's replica set.
  2626. This function aborts the seeding or tombstoning process by
  2627. stopping the service, deleting the state from the registry,
  2628. cleaning up the active threads and the active RPC calls,
  2629. and finally resetting the service to its pre-seeding/tombstoning
  2630. state.
  2631. Arguments:
  2632. None.
  2633. Return Value:
  2634. Win32 Status
  2635. --*/
  2636. {
  2637. #undef NTFRSAPI_MODULE
  2638. #define NTFRSAPI_MODULE "NtFrsApi_Abort:"
  2639. DWORD WStatus;
  2640. SERVICE_STATUS ServiceStatus;
  2641. PNTFRSAPI_THREAD Thread;
  2642. HKEY HKey = 0;
  2643. SC_HANDLE ServiceHandle = NULL;
  2644. WCHAR KeyBuf[MAX_PATH + 1];
  2645. try {
  2646. //
  2647. // Acquire all locks
  2648. //
  2649. EnterCriticalSection(&NtFrsApi_GlobalLock);
  2650. EnterCriticalSection(&NtFrsApi_ThreadLock);
  2651. NTFRSAPI_DBG_PRINT0("Abort: \n");
  2652. //
  2653. // This function is designed to be called once!
  2654. //
  2655. if (NtFrsApi_State != NTFRSAPI_PREPARED &&
  2656. NtFrsApi_State != NTFRSAPI_PREPARED_SERVICE) {
  2657. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  2658. goto done;
  2659. }
  2660. NtFrsApi_State = NTFRSAPI_ABORTING;
  2661. //
  2662. // Stop the service, kill off the active threads,
  2663. // delete old state from the registry, and restart
  2664. // the service if it was running prior to the call
  2665. // to NtFrsApi_PrepareForPromotionW.
  2666. //
  2667. try {
  2668. //
  2669. // Set the shutdown event
  2670. //
  2671. SetEvent(NtFrsApi_ShutDownEvent);
  2672. //
  2673. // Abort the threads
  2674. //
  2675. NTFRSAPI_DBG_PRINT0("Abort: threads\n");
  2676. while (Thread = NtFrsApi_Threads) {
  2677. NtFrsApi_Threads = Thread->Next;
  2678. NtFrsApi_FreeThread(Thread);
  2679. }
  2680. //
  2681. // Open the service
  2682. //
  2683. WStatus = NtFrsApi_GetServiceHandle(NULL, &ServiceHandle);
  2684. if (!WIN_SUCCESS(WStatus)) {
  2685. goto cleanup;
  2686. }
  2687. //
  2688. // Get the service's state
  2689. //
  2690. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  2691. WStatus = GetLastError();
  2692. NTFRSAPI_DBG_PRINT1("Abort: QueryServiceStatus(); %d\n", WStatus);
  2693. goto cleanup;
  2694. }
  2695. //
  2696. // Stop the service
  2697. //
  2698. NTFRSAPI_DBG_PRINT0("Abort: service\n");
  2699. if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  2700. WStatus = NtFrsApi_StopService(ServiceHandle, &ServiceStatus);
  2701. if (!WIN_SUCCESS(WStatus)) {
  2702. goto cleanup;
  2703. }
  2704. }
  2705. //
  2706. // Delete old state from the registry
  2707. //
  2708. //
  2709. // Open the ntfrs parameters\sysvol section in the registry
  2710. //
  2711. NTFRSAPI_DBG_PRINT0("Abort: registry\n");
  2712. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  2713. NULL,
  2714. FRS_SYSVOL_SECTION,
  2715. KEY_ALL_ACCESS,
  2716. &HKey);
  2717. if (!WIN_SUCCESS(WStatus)) {
  2718. goto cleanup;
  2719. }
  2720. //
  2721. // Delete the value that indicates the sysvol subkeys are valid
  2722. //
  2723. WStatus = NtFrsApiDeleteValue(NTFRSAPI_MODULE,
  2724. NULL,
  2725. FRS_SYSVOL_SECTION,
  2726. HKey,
  2727. SYSVOL_INFO_IS_COMMITTED);
  2728. if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_FILE_NOT_FOUND) {
  2729. goto cleanup;
  2730. }
  2731. //
  2732. // Delete the subkeys
  2733. //
  2734. do {
  2735. WStatus = RegEnumKey(HKey, 0, KeyBuf, MAX_PATH + 1);
  2736. if (WIN_SUCCESS(WStatus)) {
  2737. WStatus = NtFrsApiDeleteKey(NTFRSAPI_MODULE,
  2738. NULL,
  2739. FRS_SYSVOL_SECTION,
  2740. HKey,
  2741. KeyBuf);
  2742. if (!WIN_SUCCESS(WStatus)) {
  2743. goto cleanup;
  2744. }
  2745. }
  2746. } while (WIN_SUCCESS(WStatus));
  2747. if (WStatus != ERROR_NO_MORE_ITEMS) {
  2748. NTFRSAPI_DBG_PRINT2("Abort: RegEnumKey(%ws); %d\n",
  2749. FRS_SYSVOL_SECTION, WStatus);
  2750. CLEANUP_CB(NULL, FRS_SYSVOL_SECTION, WStatus, cleanup);
  2751. }
  2752. //
  2753. // Restart the service if needed
  2754. //
  2755. if (NtFrsApi_ServiceState == SERVICE_RUNNING) {
  2756. NTFRSAPI_DBG_PRINT0("Abort: restarting\n");
  2757. if (!StartService(ServiceHandle, 0, NULL)) {
  2758. WStatus = GetLastError();
  2759. NTFRSAPI_DBG_PRINT2("Abort: StartService(%ws); %d\n",
  2760. NtFrsApi_ServiceLongName, WStatus);
  2761. CLEANUP_CB(NULL, NtFrsApi_ServiceLongName, WStatus, cleanup);
  2762. }
  2763. //
  2764. // Wait for the service to start
  2765. //
  2766. WStatus = NtFrsApi_WaitForService(ServiceHandle,
  2767. NtFrsApi_ServiceWaitHint,
  2768. SERVICE_START_PENDING,
  2769. SERVICE_RUNNING);
  2770. if (!WIN_SUCCESS(WStatus)) {
  2771. WStatus = FRS_ERR_STARTING_SERVICE;
  2772. goto cleanup;
  2773. }
  2774. }
  2775. //
  2776. // Success
  2777. //
  2778. WStatus = ERROR_SUCCESS;
  2779. NtFrsApi_State = NTFRSAPI_ABORTED;
  2780. cleanup:;
  2781. } except (EXCEPTION_EXECUTE_HANDLER) {
  2782. //
  2783. // Exception (may be RPC)
  2784. //
  2785. GET_EXCEPTION_CODE(WStatus);
  2786. }
  2787. //
  2788. // Clean up any handles, events, memory, ...
  2789. //
  2790. try {
  2791. if (ServiceHandle) {
  2792. CloseServiceHandle(ServiceHandle);
  2793. }
  2794. if (HANDLE_IS_VALID(HKey)) {
  2795. RegCloseKey(HKey);
  2796. }
  2797. } except (EXCEPTION_EXECUTE_HANDLER) {
  2798. //
  2799. // Exception (may be RPC)
  2800. //
  2801. GET_EXCEPTION_CODE(WStatus);
  2802. }
  2803. done:;
  2804. } finally {
  2805. //
  2806. // Release locks
  2807. //
  2808. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  2809. LeaveCriticalSection(&NtFrsApi_ThreadLock);
  2810. if (AbnormalTermination()) {
  2811. WStatus = FRS_ERR_INTERNAL_API;
  2812. }
  2813. }
  2814. NTFRSAPI_DBG_PRINT1("Abort done: %d\n", WStatus);
  2815. return WStatus;
  2816. }
  2817. DWORD
  2818. WINAPI
  2819. NtFrsApi_AbortPromotionW(
  2820. VOID
  2821. )
  2822. /*++
  2823. Routine Description:
  2824. The NtFrs service seeds the system volume during the promotion
  2825. of a server to a Domain Controller (DC). The files and directories
  2826. for the system volume come from the same machine that is supplying
  2827. the initial Directory Service (DS).
  2828. This function aborts the seeding process by stopping the service,
  2829. deleting the promotion state out of the registry, cleaning up
  2830. the active threads and the active RPC calls, and finally resetting
  2831. the service to its pre-seeding state.
  2832. Arguments:
  2833. None.
  2834. Return Value:
  2835. Win32 Status
  2836. --*/
  2837. {
  2838. #undef NTFRSAPI_MODULE
  2839. #define NTFRSAPI_MODULE "NtFrsApi_AbortPromotionW:"
  2840. DWORD WStatus;
  2841. NTFRSAPI_DBG_PRINT0("Abort promotion: \n");
  2842. WStatus = NtFrsApi_Abort();
  2843. NTFRSAPI_DBG_PRINT1("Abort promotion done: %d\n", WStatus);
  2844. NTFRSAPI_DBG_UNPREPARE();
  2845. return WStatus;
  2846. }
  2847. DWORD
  2848. WINAPI
  2849. NtFrsApi_AbortDemotionW(
  2850. VOID
  2851. )
  2852. /*++
  2853. Routine Description:
  2854. The NtFrs service replicates the enterprise system volume to all
  2855. Domain Controllers (DCs) and replicates the domain system volume
  2856. to the DCs in a domain until the DC is demoted to a member server.
  2857. Replication is stopped by tombstoning the system volume's replica
  2858. set.
  2859. This function aborts the tombstoning process by stopping the service,
  2860. deleting the demotion state out of the registry, cleaning up
  2861. the active threads and the active RPC calls, and finally resetting
  2862. the service to its pre-tombstoning state.
  2863. Arguments:
  2864. None.
  2865. Return Value:
  2866. Win32 Status
  2867. --*/
  2868. {
  2869. #undef NTFRSAPI_MODULE
  2870. #define NTFRSAPI_MODULE "NtFrsApi_AbortDemotionW:"
  2871. DWORD WStatus;
  2872. NTFRSAPI_DBG_PRINT0("Abort demotion:\n");
  2873. WStatus = NtFrsApi_Abort();
  2874. NTFRSAPI_DBG_PRINT1("Abort demotion done: %d\n", WStatus);
  2875. NTFRSAPI_DBG_UNPREPARE();
  2876. return WStatus;
  2877. }
  2878. DWORD
  2879. WINAPI
  2880. NtFrsApi_StartPromotion_Thread(
  2881. IN PNTFRSAPI_THREAD Thread
  2882. )
  2883. /*++
  2884. Routine Description:
  2885. THIS FUNCTION IS A THREAD ENTRY!
  2886. The NtFrs service seeds the system volume during the promotion
  2887. of a server to a Domain Controller (DC). The files and directories
  2888. for the system volume come from the same machine that is supplying
  2889. the initial Directory Service (DS).
  2890. This thread that updates the sysvol information in the registry
  2891. and initiates the seeding process. The thread tracks the progress
  2892. of the seeding and periodically informs the caller.
  2893. The threads started by NtFrsApi_StartPromotionW can be forcefully
  2894. terminated with NtFrsApi_AbortPromotionW.
  2895. The threads started by NtFrsApi_StartPromotionW can be waited on
  2896. with NtFrsApi_WaitForPromotionW.
  2897. Arguments:
  2898. Thread - thread context
  2899. Return Value:
  2900. Win32 Status and updates to the thread context.
  2901. --*/
  2902. {
  2903. #undef NTFRSAPI_MODULE
  2904. #define NTFRSAPI_MODULE "NtFrsApi_StartPromotion_Thread:"
  2905. DWORD WStatus, WStatus1;
  2906. DWORD WaitStatus;
  2907. HKEY HKey = 0;
  2908. HKEY HSubKey = 0;
  2909. handle_t Handle = NULL;
  2910. try {
  2911. try {
  2912. //
  2913. // Abort client RPC calls on demand
  2914. //
  2915. WStatus = RpcMgmtSetCancelTimeout(0);
  2916. if (!WIN_SUCCESS(WStatus)) {
  2917. NTFRSAPI_DBG_PRINT1("Promotion thread start: RpcMgmtSetCancelTimeout(); %d\n",
  2918. WStatus);
  2919. CLEANUP_CB(Thread->ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  2920. }
  2921. NTFRSAPI_DBG_PRINT1("Promotion thread start: Parent %ws\n", Thread->ParentComputer);
  2922. NTFRSAPI_DBG_PRINT1("Promotion thread start: Account %ws\n", Thread->ParentAccount);
  2923. NTFRSAPI_DBG_PRINT1("Promotion thread start: Set %ws\n", Thread->ReplicaSetName);
  2924. NTFRSAPI_DBG_PRINT1("Promotion thread start: Type %ws\n", Thread->ReplicaSetType);
  2925. NTFRSAPI_DBG_PRINT1("Promotion thread start: Primary %d\n", Thread->ReplicaSetPrimary);
  2926. NTFRSAPI_DBG_PRINT1("Promotion thread start: Stage %ws\n", Thread->ReplicaSetStage);
  2927. NTFRSAPI_DBG_PRINT1("Promotion thread start: Root %ws\n", Thread->ReplicaSetRoot);
  2928. //
  2929. // Update the registry and initiate the seeding process
  2930. //
  2931. //
  2932. // Set new state in the registry
  2933. //
  2934. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  2935. Thread->ErrorCallBack,
  2936. FRS_SYSVOL_SECTION,
  2937. KEY_ALL_ACCESS,
  2938. &HKey);
  2939. if (!WIN_SUCCESS(WStatus)) {
  2940. goto cleanup;
  2941. }
  2942. //
  2943. // Create the subkey for this set
  2944. //
  2945. WStatus = NtFrsApiCreateKey(NTFRSAPI_MODULE,
  2946. Thread->ErrorCallBack,
  2947. FRS_SYSVOL_SECTION,
  2948. HKey,
  2949. Thread->ReplicaSetName,
  2950. &HSubKey);
  2951. if (!WIN_SUCCESS(WStatus)) {
  2952. goto cleanup;
  2953. }
  2954. //
  2955. // Set the subkey's values
  2956. //
  2957. //
  2958. // Replica set parent
  2959. //
  2960. if (Thread->ParentComputer) {
  2961. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  2962. Thread->ErrorCallBack,
  2963. FRS_SYSVOL_SECTION,
  2964. HSubKey,
  2965. REPLICA_SET_PARENT,
  2966. REG_SZ,
  2967. (PCHAR)Thread->ParentComputer,
  2968. (wcslen(Thread->ParentComputer) + 1) * sizeof(WCHAR));
  2969. if (!WIN_SUCCESS(WStatus)) {
  2970. goto cleanup;
  2971. }
  2972. }
  2973. //
  2974. // Replica set command
  2975. //
  2976. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  2977. Thread->ErrorCallBack,
  2978. FRS_SYSVOL_SECTION,
  2979. HSubKey,
  2980. REPLICA_SET_COMMAND,
  2981. REG_SZ,
  2982. (PCHAR)L"Create",
  2983. (wcslen(L"Create") + 1) * sizeof(WCHAR));
  2984. if (!WIN_SUCCESS(WStatus)) {
  2985. goto cleanup;
  2986. }
  2987. //
  2988. // Replica set name
  2989. //
  2990. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  2991. Thread->ErrorCallBack,
  2992. FRS_SYSVOL_SECTION,
  2993. HSubKey,
  2994. REPLICA_SET_NAME,
  2995. REG_SZ,
  2996. (PCHAR)Thread->ReplicaSetName,
  2997. (wcslen(Thread->ReplicaSetName) + 1) * sizeof(WCHAR));
  2998. if (!WIN_SUCCESS(WStatus)) {
  2999. goto cleanup;
  3000. }
  3001. //
  3002. // Replica set type
  3003. //
  3004. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3005. Thread->ErrorCallBack,
  3006. FRS_SYSVOL_SECTION,
  3007. HSubKey,
  3008. REPLICA_SET_TYPE,
  3009. REG_SZ,
  3010. (PCHAR)Thread->ReplicaSetType,
  3011. (wcslen(Thread->ReplicaSetType) + 1) * sizeof(WCHAR));
  3012. if (!WIN_SUCCESS(WStatus)) {
  3013. goto cleanup;
  3014. }
  3015. //
  3016. // Replica set primary
  3017. //
  3018. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3019. Thread->ErrorCallBack,
  3020. FRS_SYSVOL_SECTION,
  3021. HSubKey,
  3022. REPLICA_SET_PRIMARY,
  3023. REG_DWORD,
  3024. (PCHAR)&Thread->ReplicaSetPrimary,
  3025. sizeof(DWORD));
  3026. if (!WIN_SUCCESS(WStatus)) {
  3027. goto cleanup;
  3028. }
  3029. //
  3030. // Replica set root
  3031. //
  3032. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3033. Thread->ErrorCallBack,
  3034. FRS_SYSVOL_SECTION,
  3035. HSubKey,
  3036. REPLICA_SET_ROOT,
  3037. REG_SZ,
  3038. (PCHAR)Thread->ReplicaSetRoot,
  3039. (wcslen(Thread->ReplicaSetRoot) + 1) * sizeof(WCHAR));
  3040. if (!WIN_SUCCESS(WStatus)) {
  3041. goto cleanup;
  3042. }
  3043. //
  3044. // Replica set stage
  3045. //
  3046. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3047. Thread->ErrorCallBack,
  3048. FRS_SYSVOL_SECTION,
  3049. HSubKey,
  3050. REPLICA_SET_STAGE,
  3051. REG_SZ,
  3052. (PCHAR)Thread->ReplicaSetStage,
  3053. (wcslen(Thread->ReplicaSetStage) + 1) * sizeof(WCHAR));
  3054. if (!WIN_SUCCESS(WStatus)) {
  3055. goto cleanup;
  3056. }
  3057. //
  3058. // Bind to the service
  3059. //
  3060. WStatus = NtFrsApi_BindForDcpromo(NULL, NULL, &Handle);
  3061. if (!WIN_SUCCESS(WStatus)) {
  3062. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3063. //
  3064. // Ignore errors until reboot
  3065. //
  3066. Thread->ServiceState = NTFRSAPI_SERVICE_DONE;
  3067. Thread->ServiceWStatus = ERROR_SUCCESS;
  3068. WStatus = ERROR_SUCCESS;
  3069. goto cleanup;
  3070. }
  3071. //
  3072. // Tell the service to start the promotion by demoting
  3073. // existing sysvols.
  3074. //
  3075. NTFRSAPI_DBG_PRINT1("Promotion thread rpc demote: Set %ws\n",
  3076. Thread->ReplicaSetName);
  3077. try {
  3078. WStatus = NtFrsApi_Rpc_StartDemotionW(Handle, L"");
  3079. } except (EXCEPTION_EXECUTE_HANDLER) {
  3080. GET_EXCEPTION_CODE(WStatus);
  3081. }
  3082. NTFRSAPI_DBG_PRINT2("Promotion thread rpc demote done: %d (%08x)\n",
  3083. WStatus, WStatus);
  3084. //
  3085. // Ignore errors; sysvol will be seeded after promotion
  3086. //
  3087. // if (!WIN_SUCCESS(WStatus)) {
  3088. // WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3089. // goto cleanup;
  3090. // }
  3091. //
  3092. //
  3093. Thread->ServiceState = NTFRSAPI_SERVICE_DONE;
  3094. Thread->ServiceWStatus = ERROR_SUCCESS;
  3095. WStatus = ERROR_SUCCESS;
  3096. //
  3097. // Success
  3098. //
  3099. WStatus = ERROR_SUCCESS;
  3100. cleanup:;
  3101. } except (EXCEPTION_EXECUTE_HANDLER) {
  3102. GET_EXCEPTION_CODE(WStatus);
  3103. }
  3104. //
  3105. // Clean up any handles, events, memory, ...
  3106. //
  3107. try {
  3108. if (HANDLE_IS_VALID(HKey)) {
  3109. RegCloseKey(HKey);
  3110. }
  3111. if (HANDLE_IS_VALID(HSubKey)) {
  3112. RegCloseKey(HSubKey);
  3113. }
  3114. if (Handle) {
  3115. WStatus1 = RpcBindingFree(&Handle);
  3116. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  3117. }
  3118. } except (EXCEPTION_EXECUTE_HANDLER) {
  3119. GET_EXCEPTION_CODE(WStatus);
  3120. }
  3121. } finally {
  3122. if (AbnormalTermination()) {
  3123. WStatus = FRS_ERR_INTERNAL_API;
  3124. }
  3125. }
  3126. Thread->ThreadWStatus = WStatus;
  3127. NTFRSAPI_DBG_PRINT1("Promotion thread complete: Set %ws\n", Thread->ReplicaSetName);
  3128. NTFRSAPI_DBG_PRINT2("Promotion thread complete: Thread %d, Service %d\n",
  3129. Thread->ThreadWStatus, Thread->ServiceWStatus);
  3130. SetEvent(Thread->DoneEvent);
  3131. return WStatus;
  3132. }
  3133. DWORD
  3134. WINAPI
  3135. NtFrsApi_StartPromotionW(
  3136. IN PWCHAR ParentComputer, OPTIONAL
  3137. IN PWCHAR ParentAccount, OPTIONAL
  3138. IN PWCHAR ParentPassword, OPTIONAL
  3139. IN DWORD DisplayCallBack(IN PWCHAR Display), OPTIONAL
  3140. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  3141. IN PWCHAR ReplicaSetName,
  3142. IN PWCHAR ReplicaSetType,
  3143. IN DWORD ReplicaSetPrimary,
  3144. IN PWCHAR ReplicaSetStage,
  3145. IN PWCHAR ReplicaSetRoot
  3146. )
  3147. /*++
  3148. Routine Description:
  3149. The NtFrs service seeds the system volume during the promotion
  3150. of a server to a Domain Controller (DC). The files and directories
  3151. for the system volume come from the same machine that is supplying
  3152. the initial Directory Service (DS).
  3153. This function kicks off a thread that updates the sysvol information
  3154. in the registry and initiates the seeding process. The thread tracks
  3155. the progress of the seeding and periodically informs the caller.
  3156. The threads started by NtFrsApi_StartPromotionW can be forcefully
  3157. terminated with NtFrsApi_AbortPromotionW.
  3158. The threads started by NtFrsApi_StartPromotionW can be waited on
  3159. with NtFrsApi_WaitForPromotionW.
  3160. Arguments:
  3161. ParentComputer - An RPC-bindable name of the computer that is
  3162. supplying the Directory Service (DS) with its
  3163. initial state. The files and directories for
  3164. the system volume are replicated from this
  3165. parent computer.
  3166. ParentAccount - A logon account on ParentComputer.
  3167. NULL == use the caller's credentials
  3168. ParentPassword - The logon account's password on ParentComputer.
  3169. DisplayCallBack - Called periodically with a progress display.
  3170. ReplicaSetName - Name of the replica set.
  3171. ReplicaSetType - Type of replica set (enterprise or domain)
  3172. ReplicaSetPrimary - Is this the primary member of the replica set?
  3173. ReplicaSetStage - Staging path.
  3174. ReplicaSetRoot - Root path.
  3175. Return Value:
  3176. Win32 Status
  3177. --*/
  3178. {
  3179. #undef NTFRSAPI_MODULE
  3180. #define NTFRSAPI_MODULE "NtFrsApi_StartPromotionW:"
  3181. DWORD WStatus, WStatus1;
  3182. handle_t Handle = NULL;
  3183. try {
  3184. //
  3185. // Acquire global lock within a try-finally
  3186. //
  3187. EnterCriticalSection(&NtFrsApi_GlobalLock);
  3188. NTFRSAPI_DBG_PRINT1("Promotion start: Parent %ws\n", ParentComputer);
  3189. NTFRSAPI_DBG_PRINT1("Promotion start: Account %ws\n", ParentAccount);
  3190. NTFRSAPI_DBG_PRINT1("Promotion start: Set %ws\n", ReplicaSetName);
  3191. NTFRSAPI_DBG_PRINT1("Promotion start: Type %ws\n", ReplicaSetType);
  3192. NTFRSAPI_DBG_PRINT1("Promotion start: Primary %d\n", ReplicaSetPrimary);
  3193. NTFRSAPI_DBG_PRINT1("Promotion start: Stage %ws\n", ReplicaSetStage);
  3194. NTFRSAPI_DBG_PRINT1("Promotion start: Root %ws\n", ReplicaSetRoot);
  3195. ParentAccount = NULL;
  3196. ParentPassword = NULL;
  3197. //
  3198. // This function is designed to be called once!
  3199. //
  3200. if (NtFrsApi_State != NTFRSAPI_PREPARED) {
  3201. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  3202. goto done;
  3203. }
  3204. //
  3205. // Update the registry and initiate the seeding process
  3206. //
  3207. try {
  3208. //
  3209. // Check parameters
  3210. //
  3211. // What about kerberos,delegation,impersonation,no account?
  3212. //
  3213. if (!ReplicaSetName ||
  3214. !ReplicaSetType ||
  3215. !ReplicaSetStage ||
  3216. !ReplicaSetRoot ||
  3217. (!ParentComputer && ReplicaSetPrimary != 1)) {
  3218. WStatus = ERROR_INVALID_PARAMETER;
  3219. goto cleanup;
  3220. }
  3221. if (WSTR_NE(ReplicaSetType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) &&
  3222. WSTR_NE(ReplicaSetType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN)) {
  3223. WStatus = ERROR_INVALID_PARAMETER;
  3224. goto cleanup;
  3225. }
  3226. if (ReplicaSetPrimary != 0 && ReplicaSetPrimary != 1) {
  3227. WStatus = ERROR_INVALID_PARAMETER;
  3228. goto cleanup;
  3229. }
  3230. WStatus = NtFrsApi_CreateThread(NtFrsApi_StartPromotion_Thread,
  3231. ParentComputer,
  3232. ParentAccount,
  3233. ParentPassword,
  3234. DisplayCallBack,
  3235. ErrorCallBack,
  3236. ReplicaSetName,
  3237. ReplicaSetType,
  3238. ReplicaSetPrimary,
  3239. ReplicaSetStage,
  3240. ReplicaSetRoot);
  3241. if (!WIN_SUCCESS(WStatus)) {
  3242. goto cleanup;
  3243. }
  3244. //
  3245. // Success
  3246. //
  3247. WStatus = ERROR_SUCCESS;
  3248. cleanup:;
  3249. } except (EXCEPTION_EXECUTE_HANDLER) {
  3250. GET_EXCEPTION_CODE(WStatus);
  3251. }
  3252. //
  3253. // Clean up any handles, events, memory, ...
  3254. //
  3255. try {
  3256. if (Handle) {
  3257. WStatus1 = RpcBindingFree(&Handle);
  3258. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  3259. }
  3260. } except (EXCEPTION_EXECUTE_HANDLER) {
  3261. GET_EXCEPTION_CODE(WStatus);
  3262. }
  3263. done:;
  3264. } finally {
  3265. //
  3266. // Release locks
  3267. //
  3268. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  3269. if (AbnormalTermination()) {
  3270. WStatus = FRS_ERR_INTERNAL_API;
  3271. }
  3272. }
  3273. NTFRSAPI_DBG_PRINT2("Promotion start done: Set %ws, %d\n",
  3274. ReplicaSetName, WStatus);
  3275. return WStatus;
  3276. }
  3277. DWORD
  3278. WINAPI
  3279. NtFrsApi_StartDemotion_Thread(
  3280. IN PNTFRSAPI_THREAD Thread
  3281. )
  3282. /*++
  3283. Routine Description:
  3284. THIS FUNCTION IS A THREAD ENTRY!
  3285. The NtFrs service replicates the enterprise system volume to all
  3286. Domain Controllers (DCs) and replicates the domain system volume
  3287. to the DCs in a domain until the DC is demoted to a member server.
  3288. Replication is stopped by tombstoning the system volume's replica
  3289. set.
  3290. This thread stops replicating the system volume by telling
  3291. the NtFrs service on this machine to tombstone the system
  3292. volume's replica set.
  3293. The threads started by NtFrsApi_StartDemotionW can be forcefully
  3294. terminated with NtFrsApi_AbortDemotionW.
  3295. The threads started by NtFrsApi_StartDemotionW can be waited on
  3296. with NtFrsApi_WaitForDemotionW.
  3297. Arguments:
  3298. Thread - thread context
  3299. Return Value:
  3300. Win32 Status and updated thread context
  3301. --*/
  3302. {
  3303. #undef NTFRSAPI_MODULE
  3304. #define NTFRSAPI_MODULE "NtFrsApi_StartDemotion_Thread:"
  3305. DWORD WStatus, WStatus1;
  3306. HKEY HKey = 0;
  3307. HKEY HSubKey = 0;
  3308. handle_t Handle = NULL;
  3309. try {
  3310. try {
  3311. //
  3312. // Abort client RPC calls on demand
  3313. //
  3314. WStatus = RpcMgmtSetCancelTimeout(0);
  3315. if (!WIN_SUCCESS(WStatus)) {
  3316. NTFRSAPI_DBG_PRINT1("Demotion thread start: RpcMgmtSetCancelTimeout(); %d\n", WStatus);
  3317. CLEANUP_CB(Thread->ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  3318. }
  3319. NTFRSAPI_DBG_PRINT1("Demotion thread start: Set %ws\n", Thread->ReplicaSetName);
  3320. //
  3321. // Update the registry and initiate the seeding process
  3322. //
  3323. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  3324. Thread->ErrorCallBack,
  3325. FRS_SYSVOL_SECTION,
  3326. KEY_ALL_ACCESS,
  3327. &HKey);
  3328. if (!WIN_SUCCESS(WStatus)) {
  3329. goto cleanup;
  3330. }
  3331. //
  3332. // Create the subkey for this set
  3333. //
  3334. WStatus = NtFrsApiCreateKey(NTFRSAPI_MODULE,
  3335. Thread->ErrorCallBack,
  3336. FRS_SYSVOL_SECTION,
  3337. HKey,
  3338. Thread->ReplicaSetName,
  3339. &HSubKey);
  3340. if (!WIN_SUCCESS(WStatus)) {
  3341. goto cleanup;
  3342. }
  3343. //
  3344. // Set the subkey's values
  3345. //
  3346. //
  3347. // Replica set command
  3348. //
  3349. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3350. Thread->ErrorCallBack,
  3351. FRS_SYSVOL_SECTION,
  3352. HSubKey,
  3353. REPLICA_SET_COMMAND,
  3354. REG_SZ,
  3355. (PCHAR)L"Delete",
  3356. (wcslen(L"Delete") + 1) * sizeof(WCHAR));
  3357. if (!WIN_SUCCESS(WStatus)) {
  3358. goto cleanup;
  3359. }
  3360. //
  3361. // Replica set name
  3362. //
  3363. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3364. Thread->ErrorCallBack,
  3365. FRS_SYSVOL_SECTION,
  3366. HSubKey,
  3367. REPLICA_SET_NAME,
  3368. REG_SZ,
  3369. (PCHAR)Thread->ReplicaSetName,
  3370. (wcslen(Thread->ReplicaSetName) + 1) * sizeof(WCHAR));
  3371. if (!WIN_SUCCESS(WStatus)) {
  3372. goto cleanup;
  3373. }
  3374. //
  3375. // Bind to the service
  3376. //
  3377. WStatus = NtFrsApi_BindForDcpromo(NULL,
  3378. Thread->ErrorCallBack,
  3379. &Handle);
  3380. if (!WIN_SUCCESS(WStatus)) {
  3381. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3382. goto cleanup;
  3383. }
  3384. //
  3385. // Tell the service to demote the sysvol
  3386. //
  3387. NTFRSAPI_DBG_PRINT1("Demotion thread rpc start: Set %ws\n",
  3388. Thread->ReplicaSetName);
  3389. try {
  3390. WStatus = NtFrsApi_Rpc_StartDemotionW(Handle,
  3391. Thread->ReplicaSetName);
  3392. } except (EXCEPTION_EXECUTE_HANDLER) {
  3393. GET_EXCEPTION_CODE(WStatus);
  3394. }
  3395. NTFRSAPI_DBG_PRINT3("Demotion thread rpc start done: Set %ws, %d (%08x)\n",
  3396. Thread->ReplicaSetName, WStatus, WStatus);
  3397. if (!WIN_SUCCESS(WStatus)) {
  3398. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3399. goto cleanup;
  3400. }
  3401. //
  3402. // Success
  3403. //
  3404. WStatus = ERROR_SUCCESS;
  3405. cleanup:;
  3406. } except (EXCEPTION_EXECUTE_HANDLER) {
  3407. GET_EXCEPTION_CODE(WStatus);
  3408. }
  3409. //
  3410. // Clean up any handles, events, memory, ...
  3411. //
  3412. try {
  3413. if (HANDLE_IS_VALID(HKey)) {
  3414. RegCloseKey(HKey);
  3415. }
  3416. if (HANDLE_IS_VALID(HSubKey)) {
  3417. RegCloseKey(HSubKey);
  3418. }
  3419. if (Handle) {
  3420. WStatus1 = RpcBindingFree(&Handle);
  3421. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  3422. }
  3423. } except (EXCEPTION_EXECUTE_HANDLER) {
  3424. GET_EXCEPTION_CODE(WStatus);
  3425. }
  3426. } finally {
  3427. if (AbnormalTermination()) {
  3428. WStatus = FRS_ERR_INTERNAL_API;
  3429. }
  3430. }
  3431. Thread->ThreadWStatus = WStatus;
  3432. Thread->ServiceState = NTFRSAPI_SERVICE_DONE;
  3433. Thread->ServiceWStatus = ERROR_SUCCESS;
  3434. NTFRSAPI_DBG_PRINT1("Demotion thread done: Set %ws\n", Thread->ReplicaSetName);
  3435. NTFRSAPI_DBG_PRINT2("Demotion thread done: Thread %d, Service %d\n",
  3436. Thread->ThreadWStatus, Thread->ServiceWStatus);
  3437. SetEvent(Thread->DoneEvent);
  3438. return WStatus;
  3439. }
  3440. DWORD
  3441. WINAPI
  3442. NtFrsApi_StartDemotionW(
  3443. IN PWCHAR ReplicaSetName,
  3444. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  3445. )
  3446. /*++
  3447. Routine Description:
  3448. The NtFrs service replicates the enterprise system volume to all
  3449. Domain Controllers (DCs) and replicates the domain system volume
  3450. to the DCs in a domain until the DC is demoted to a member server.
  3451. Replication is stopped by tombstoning the system volume's replica
  3452. set.
  3453. This function kicks off a thread that stops replicating the
  3454. system volume by telling the NtFrs service on this machine
  3455. to tombstone the system volume's replica set.
  3456. The threads started by NtFrsApi_StartDemotionW can be forcefully
  3457. terminated with NtFrsApi_AbortDemotionW.
  3458. The threads started by NtFrsApi_StartDemotionW can be waited on
  3459. with NtFrsApi_WaitForDemotionW.
  3460. Arguments:
  3461. ReplicaSetName - Name of the replica set.
  3462. Return Value:
  3463. Win32 Status
  3464. --*/
  3465. {
  3466. #undef NTFRSAPI_MODULE
  3467. #define NTFRSAPI_MODULE "NtFrsApi_StartDemotionW:"
  3468. DWORD WStatus;
  3469. try {
  3470. //
  3471. // Acquire global lock within a try-finally
  3472. //
  3473. EnterCriticalSection(&NtFrsApi_GlobalLock);
  3474. NTFRSAPI_DBG_PRINT1("Demotion start: Set %ws\n", ReplicaSetName);
  3475. //
  3476. // This function is designed to be called once!
  3477. //
  3478. if (NtFrsApi_State != NTFRSAPI_PREPARED) {
  3479. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  3480. goto done;
  3481. }
  3482. //
  3483. // Update the registry and initiate the seeding process
  3484. //
  3485. try {
  3486. //
  3487. // Check parameters
  3488. //
  3489. if (!ReplicaSetName) {
  3490. WStatus = ERROR_INVALID_PARAMETER;
  3491. goto cleanup;
  3492. }
  3493. //
  3494. // Create the demotion thread
  3495. //
  3496. WStatus = NtFrsApi_CreateThread(NtFrsApi_StartDemotion_Thread,
  3497. NULL,
  3498. NULL,
  3499. NULL,
  3500. NULL,
  3501. ErrorCallBack,
  3502. ReplicaSetName,
  3503. NULL,
  3504. 0,
  3505. NULL,
  3506. NULL);
  3507. if (!WIN_SUCCESS(WStatus)) {
  3508. goto cleanup;
  3509. }
  3510. //
  3511. // Success
  3512. //
  3513. WStatus = ERROR_SUCCESS;
  3514. cleanup:;
  3515. } except (EXCEPTION_EXECUTE_HANDLER) {
  3516. GET_EXCEPTION_CODE(WStatus);
  3517. }
  3518. //
  3519. // Clean up any handles, events, memory, ...
  3520. //
  3521. try {
  3522. } except (EXCEPTION_EXECUTE_HANDLER) {
  3523. GET_EXCEPTION_CODE(WStatus);
  3524. }
  3525. done:;
  3526. } finally {
  3527. //
  3528. // Release locks
  3529. //
  3530. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  3531. if (AbnormalTermination()) {
  3532. WStatus = FRS_ERR_INTERNAL_API;
  3533. }
  3534. }
  3535. NTFRSAPI_DBG_PRINT2("Demotion start done: Set %ws %d\n",
  3536. ReplicaSetName, WStatus);
  3537. return WStatus;
  3538. }
  3539. DWORD
  3540. WINAPI
  3541. NtFrsApi_Wait(
  3542. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  3543. IN DWORD TimeoutInMilliSeconds
  3544. )
  3545. /*++
  3546. Routine Description:
  3547. The NtFrs service seeds the system volume during the promotion
  3548. of a server to a Domain Controller (DC) and stops replicating
  3549. the system volumes when a DC is demoted to a member server.
  3550. Replication is stopped by tombstoning the system volume's replica
  3551. set.
  3552. This function waits for the seeding or tombstoning to finish
  3553. or to stop w/error.
  3554. NOT MT-SAFE.
  3555. Arguments:
  3556. TimeoutInMilliSeconds - Timeout in milliseconds for waiting for
  3557. seeding/tombstoning to finish.
  3558. ErrorCallBack - Ignored if NULL. Called with additional
  3559. info about an error.
  3560. Return Value:
  3561. Win32 Status
  3562. --*/
  3563. {
  3564. #undef NTFRSAPI_MODULE
  3565. #define NTFRSAPI_MODULE "NtFrsApi_Wait:"
  3566. DWORD WStatus;
  3567. DWORD WaitStatus;
  3568. DWORD i;
  3569. PNTFRSAPI_THREAD Thread;
  3570. HANDLE *Handles = NULL;
  3571. WStatus = ERROR_SUCCESS;
  3572. try {
  3573. //
  3574. // Acquire all locks
  3575. //
  3576. EnterCriticalSection(&NtFrsApi_GlobalLock);
  3577. EnterCriticalSection(&NtFrsApi_ThreadLock);
  3578. NTFRSAPI_DBG_PRINT0("Wait: \n");
  3579. //
  3580. // Nothing to wait on
  3581. //
  3582. if (NtFrsApi_State != NTFRSAPI_PREPARED) {
  3583. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  3584. goto done;
  3585. }
  3586. try {
  3587. //
  3588. // Collect the done events
  3589. //
  3590. NTFRSAPI_DBG_PRINT0("Wait: Threads\n");
  3591. Handles = NtFrsApi_Alloc(NtFrsApi_NumberOfThreads * sizeof(HANDLE));
  3592. for (Thread = NtFrsApi_Threads, i = 0;
  3593. Thread && i < NtFrsApi_NumberOfThreads;
  3594. Thread = Thread->Next, ++i) {
  3595. Handles[i] = Thread->DoneEvent;
  3596. }
  3597. //
  3598. // Wait on the threads' done events
  3599. //
  3600. WaitStatus = WaitForMultipleObjects(NtFrsApi_NumberOfThreads,
  3601. Handles,
  3602. TRUE,
  3603. TimeoutInMilliSeconds);
  3604. //
  3605. // Timeout
  3606. //
  3607. if (WaitStatus == WAIT_TIMEOUT) {
  3608. WStatus = ERROR_TIMEOUT;
  3609. goto cleanup;
  3610. }
  3611. //
  3612. // Wait failed
  3613. //
  3614. if (WaitStatus == WAIT_FAILED) {
  3615. WStatus = GetLastError();
  3616. NTFRSAPI_DBG_PRINT1("%s WaitForMultipleObjects(); %d\n", WStatus);
  3617. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  3618. }
  3619. //
  3620. // Return the threads' status
  3621. //
  3622. NTFRSAPI_DBG_PRINT0("Wait: Status\n");
  3623. for (Thread = NtFrsApi_Threads; Thread; Thread = Thread->Next) {
  3624. //
  3625. // Thread error
  3626. //
  3627. WStatus = Thread->ThreadWStatus;
  3628. if (!WIN_SUCCESS(WStatus)) {
  3629. goto cleanup;
  3630. }
  3631. //
  3632. // Service error
  3633. //
  3634. WStatus = Thread->ServiceWStatus;
  3635. if (!WIN_SUCCESS(WStatus)) {
  3636. goto cleanup;
  3637. }
  3638. }
  3639. cleanup:;
  3640. } except (EXCEPTION_EXECUTE_HANDLER) {
  3641. GET_EXCEPTION_CODE(WStatus);
  3642. }
  3643. //
  3644. // Clean up any handles, events, memory, ...
  3645. //
  3646. try {
  3647. FREE(Handles);
  3648. } except (EXCEPTION_EXECUTE_HANDLER) {
  3649. GET_EXCEPTION_CODE(WStatus);
  3650. }
  3651. done:;
  3652. } finally {
  3653. //
  3654. // Release locks
  3655. //
  3656. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  3657. LeaveCriticalSection(&NtFrsApi_ThreadLock);
  3658. if (AbnormalTermination()) {
  3659. WStatus = FRS_ERR_INTERNAL_API;
  3660. }
  3661. }
  3662. NTFRSAPI_DBG_PRINT1("Wait done: %d\n", WStatus);
  3663. return WStatus;
  3664. }
  3665. DWORD
  3666. WINAPI
  3667. NtFrsApi_WaitForPromotionW(
  3668. IN DWORD TimeoutInMilliSeconds,
  3669. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  3670. )
  3671. /*++
  3672. Routine Description:
  3673. The NtFrs service seeds the system volume during the promotion
  3674. of a server to a Domain Controller (DC). The files and directories
  3675. for the system volume come from the same machine that is supplying
  3676. the initial Directory Service (DS).
  3677. This function waits for the seeding to finish or to stop w/error.
  3678. Arguments:
  3679. TimeoutInMilliSeconds - Timeout in milliseconds for waiting for
  3680. seeding to finish.
  3681. Return Value:
  3682. Win32 Status
  3683. --*/
  3684. {
  3685. #undef NTFRSAPI_MODULE
  3686. #define NTFRSAPI_MODULE "NtFrsApi_WaitForPromotionW:"
  3687. DWORD WStatus;
  3688. NTFRSAPI_DBG_PRINT0("Wait promotion: \n");
  3689. WStatus = NtFrsApi_Wait(ErrorCallBack, TimeoutInMilliSeconds);
  3690. NTFRSAPI_DBG_PRINT1("Wait promotion done: %d\n", WStatus);
  3691. if (!WIN_SUCCESS(WStatus)) {
  3692. NtFrsApi_AbortPromotionW();
  3693. }
  3694. return WStatus;
  3695. }
  3696. DWORD
  3697. WINAPI
  3698. NtFrsApi_WaitForDemotionW(
  3699. IN DWORD TimeoutInMilliSeconds,
  3700. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  3701. )
  3702. /*++
  3703. Routine Description:
  3704. The NtFrs service replicates the enterprise system volume to all
  3705. Domain Controllers (DCs) and replicates the domain system volume
  3706. to the DCs in a domain until the DC is demoted to a member server.
  3707. Replication is stopped by tombstoning the system volume's replica
  3708. set.
  3709. This function waits for the tombstoning to finish or to stop w/error.
  3710. Arguments:
  3711. TimeoutInMilliSeconds - Timeout in milliseconds for waiting for
  3712. tombstoning to finish.
  3713. Return Value:
  3714. Win32 Status
  3715. --*/
  3716. {
  3717. #undef NTFRSAPI_MODULE
  3718. #define NTFRSAPI_MODULE "NtFrsApi_WaitForDemotionW:"
  3719. DWORD WStatus;
  3720. NTFRSAPI_DBG_PRINT0("Wait demotion: \n");
  3721. WStatus = NtFrsApi_Wait(ErrorCallBack, TimeoutInMilliSeconds);
  3722. NTFRSAPI_DBG_PRINT1("Wait demotion done: %d\n", WStatus);
  3723. if (!WIN_SUCCESS(WStatus)) {
  3724. NtFrsApi_AbortDemotionW();
  3725. }
  3726. return WStatus;
  3727. }
  3728. DWORD
  3729. WINAPI
  3730. NtFrsApi_CommitPromotionW(
  3731. IN DWORD TimeoutInMilliSeconds,
  3732. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  3733. )
  3734. /*++
  3735. Routine Description:
  3736. WARNING - This function assumes the caller will reboot the system
  3737. soon after this call!
  3738. The NtFrs service seeds the system volume during the promotion
  3739. of a server to a Domain Controller (DC). The files and directories
  3740. for the system volume come from the same machine that is supplying
  3741. the initial Directory Service (DS).
  3742. This function waits for the seeding to finish, stops the service,
  3743. and commits the state in the registry. On reboot, the NtFrs Service
  3744. updates the DS on this machine with the information in the registry.
  3745. Arguments:
  3746. TimeoutInMilliSeconds - Timeout in milliseconds for waiting for
  3747. seeding to finish.
  3748. Return Value:
  3749. Win32 Status
  3750. --*/
  3751. {
  3752. #undef NTFRSAPI_MODULE
  3753. #define NTFRSAPI_MODULE "NtFrsApi_CommitPromotionW:"
  3754. DWORD WStatus;
  3755. SERVICE_STATUS ServiceStatus;
  3756. DWORD SysVolInfoIsCommitted = 1;
  3757. DWORD SysvolReady = 0;
  3758. HKEY HKey = 0;
  3759. SC_HANDLE ServiceHandle = NULL;
  3760. //
  3761. // Wait for the seeding to finish.
  3762. //
  3763. WStatus = NtFrsApi_WaitForPromotionW(TimeoutInMilliSeconds, ErrorCallBack);
  3764. if (!WIN_SUCCESS(WStatus)) {
  3765. NTFRSAPI_DBG_PRINT1("Commit promotion aborted: %d\n", WStatus);
  3766. NTFRSAPI_DBG_FLUSH();
  3767. return WStatus;
  3768. }
  3769. try {
  3770. //
  3771. // Acquire global lock within a try-finally
  3772. //
  3773. EnterCriticalSection(&NtFrsApi_GlobalLock);
  3774. NTFRSAPI_DBG_PRINT0("Commit promotion:\n");
  3775. //
  3776. // This function is designed to be called once!
  3777. //
  3778. if (NtFrsApi_State != NTFRSAPI_PREPARED) {
  3779. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  3780. goto done;
  3781. }
  3782. NtFrsApi_State = NTFRSAPI_COMMITTING;
  3783. //
  3784. // Stop the service and commit the new state in the registry
  3785. //
  3786. try {
  3787. //
  3788. // Open the service
  3789. //
  3790. NTFRSAPI_DBG_PRINT0("Commit promotion: service\n");
  3791. WStatus = NtFrsApi_GetServiceHandle(ErrorCallBack, &ServiceHandle);
  3792. if (!WIN_SUCCESS(WStatus)) {
  3793. goto cleanup;
  3794. }
  3795. //
  3796. // Stop the service
  3797. //
  3798. WStatus = NtFrsApi_StopService(ServiceHandle, &ServiceStatus);
  3799. if (!WIN_SUCCESS(WStatus)) {
  3800. goto cleanup;
  3801. }
  3802. //
  3803. // Commit the new state in the registry
  3804. //
  3805. //
  3806. // Open the ntfrs parameters\sysvol section in the registry
  3807. //
  3808. NTFRSAPI_DBG_PRINT0("Commit promotion: registry\n");
  3809. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  3810. ErrorCallBack,
  3811. FRS_SYSVOL_SECTION,
  3812. KEY_ALL_ACCESS,
  3813. &HKey);
  3814. if (!WIN_SUCCESS(WStatus)) {
  3815. goto cleanup;
  3816. }
  3817. //
  3818. // Set the value that indicates the sysvol subkeys are valid
  3819. //
  3820. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  3821. ErrorCallBack,
  3822. FRS_SYSVOL_SECTION,
  3823. HKey,
  3824. SYSVOL_INFO_IS_COMMITTED,
  3825. REG_DWORD,
  3826. (PCHAR)&SysVolInfoIsCommitted,
  3827. sizeof(SysVolInfoIsCommitted));
  3828. if (!WIN_SUCCESS(WStatus)) {
  3829. goto cleanup;
  3830. }
  3831. //
  3832. // Service starts automatically at startup
  3833. //
  3834. if (!ChangeServiceConfig(ServiceHandle,
  3835. SERVICE_NO_CHANGE,
  3836. SERVICE_AUTO_START,
  3837. SERVICE_NO_CHANGE,
  3838. NULL,
  3839. NULL,
  3840. NULL,
  3841. NULL,
  3842. NULL,
  3843. NULL,
  3844. NtFrsApi_ServiceLongName)) {
  3845. WStatus = GetLastError();
  3846. NTFRSAPI_DBG_PRINT1("Commit promotion: no auto %d\n", WStatus);
  3847. }
  3848. //
  3849. // Success
  3850. //
  3851. NtFrsApi_State = NTFRSAPI_COMMITTED;
  3852. WStatus = ERROR_SUCCESS;
  3853. cleanup:;
  3854. } except (EXCEPTION_EXECUTE_HANDLER) {
  3855. //
  3856. // Exception (may be RPC)
  3857. //
  3858. GET_EXCEPTION_CODE(WStatus);
  3859. }
  3860. //
  3861. // Clean up any handles, events, memory, ...
  3862. //
  3863. try {
  3864. if (ServiceHandle) {
  3865. CloseServiceHandle(ServiceHandle);
  3866. }
  3867. if (HANDLE_IS_VALID(HKey)) {
  3868. RegCloseKey(HKey);
  3869. }
  3870. } except (EXCEPTION_EXECUTE_HANDLER) {
  3871. //
  3872. // Exception (may be RPC)
  3873. //
  3874. GET_EXCEPTION_CODE(WStatus);
  3875. }
  3876. done:;
  3877. } finally {
  3878. //
  3879. // Release locks
  3880. //
  3881. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  3882. if (AbnormalTermination()) {
  3883. WStatus = FRS_ERR_INTERNAL_API;
  3884. }
  3885. }
  3886. NTFRSAPI_DBG_PRINT1("Commit promotion done: %d\n", WStatus);
  3887. NTFRSAPI_DBG_UNPREPARE();
  3888. return WStatus;
  3889. }
  3890. DWORD
  3891. WINAPI
  3892. NtFrsApi_CommitDemotionW(
  3893. IN DWORD TimeoutInMilliSeconds,
  3894. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  3895. )
  3896. /*++
  3897. Routine Description:
  3898. WARNING - This function assumes the caller will reboot the system
  3899. soon after this call!
  3900. The NtFrs service replicates the enterprise system volume to all
  3901. Domain Controllers (DCs) and replicates the domain system volume
  3902. to the DCs in a domain until the DC is demoted to a member server
  3903. by tombstoning the system volume's replica set.
  3904. This function waits for the tombstoning to finish, tells the service
  3905. to forcibly delete the system volumes' replica sets, stops the service,
  3906. and commits the state in the registry. On reboot, the NtFrs Service
  3907. updates the DS on this machine with the information in the registry.
  3908. Arguments:
  3909. TimeoutInMilliSeconds - Timeout in milliseconds for waiting for
  3910. tombstoning to finish.
  3911. Return Value:
  3912. Win32 Status
  3913. --*/
  3914. {
  3915. #undef NTFRSAPI_MODULE
  3916. #define NTFRSAPI_MODULE "NtFrsApi_CommitDemotionW:"
  3917. DWORD WStatus, WStatus1;
  3918. SERVICE_STATUS ServiceStatus;
  3919. DWORD SysVolInfoIsCommitted = 1;
  3920. DWORD SysvolReady = 0;
  3921. HKEY HKey = 0;
  3922. HKEY HNetKey = 0;
  3923. SC_HANDLE ServiceHandle = NULL;
  3924. handle_t RpcHandle = NULL;
  3925. //
  3926. // Wait for the demotion to finish.
  3927. //
  3928. WStatus = NtFrsApi_WaitForDemotionW(TimeoutInMilliSeconds, ErrorCallBack);
  3929. if (!WIN_SUCCESS(WStatus)) {
  3930. NTFRSAPI_DBG_PRINT1("Commit demotion aborted: %d\n", WStatus);
  3931. NTFRSAPI_DBG_FLUSH();
  3932. return WStatus;
  3933. }
  3934. try {
  3935. //
  3936. // Acquire global lock within a try-finally
  3937. //
  3938. EnterCriticalSection(&NtFrsApi_GlobalLock);
  3939. NTFRSAPI_DBG_PRINT0("Commit demotion:\n");
  3940. //
  3941. // This function is designed to be called once!
  3942. //
  3943. if (NtFrsApi_State != NTFRSAPI_PREPARED) {
  3944. WStatus = FRS_ERR_INVALID_API_SEQUENCE;
  3945. goto done;
  3946. }
  3947. NtFrsApi_State = NTFRSAPI_COMMITTING;
  3948. //
  3949. // Stop the service and commit the new state in the registry
  3950. //
  3951. try {
  3952. //
  3953. // Set the RPC cancel timeout to "now"
  3954. //
  3955. WStatus = RpcMgmtSetCancelTimeout(0);
  3956. if (!WIN_SUCCESS(WStatus)) {
  3957. NTFRSAPI_DBG_PRINT1("Commit demotion: RpcMgmtSetCancelTimeout(); %d\n", WStatus);
  3958. CLEANUP_CB(ErrorCallBack, NtFrsApi_ServiceLongName, WStatus, cleanup);
  3959. }
  3960. //
  3961. // Bind to the service
  3962. //
  3963. NTFRSAPI_DBG_PRINT0("Commit demotion: service\n");
  3964. WStatus = NtFrsApi_BindForDcpromo(NULL, ErrorCallBack, &RpcHandle);
  3965. if (!WIN_SUCCESS(WStatus)) {
  3966. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3967. goto cleanup;
  3968. }
  3969. //
  3970. // Tell the service to commit the demotion
  3971. //
  3972. NTFRSAPI_DBG_PRINT0("Commit demotion rpc start:\n");
  3973. try {
  3974. WStatus = NtFrsApi_Rpc_CommitDemotionW(RpcHandle);
  3975. } except (EXCEPTION_EXECUTE_HANDLER) {
  3976. GET_EXCEPTION_CODE(WStatus);
  3977. }
  3978. NTFRSAPI_DBG_PRINT2("Commit demotion rpc done: %d (%08x)\n",
  3979. WStatus, WStatus);
  3980. if (!WIN_SUCCESS(WStatus)) {
  3981. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  3982. goto cleanup;
  3983. }
  3984. //
  3985. // Open the service
  3986. //
  3987. WStatus = NtFrsApi_GetServiceHandle(ErrorCallBack, &ServiceHandle);
  3988. if (!WIN_SUCCESS(WStatus)) {
  3989. goto cleanup;
  3990. }
  3991. //
  3992. // Stop the service
  3993. //
  3994. NTFRSAPI_DBG_PRINT0("Commit demotion: stop service\n");
  3995. WStatus = NtFrsApi_StopService(ServiceHandle, &ServiceStatus);
  3996. if (!WIN_SUCCESS(WStatus)) {
  3997. goto cleanup;
  3998. }
  3999. //
  4000. // Commit the new state in the registry
  4001. //
  4002. //
  4003. // Open the ntfrs parameters\sysvol section in the registry
  4004. //
  4005. NTFRSAPI_DBG_PRINT0("Commit demotion: registry\n");
  4006. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  4007. ErrorCallBack,
  4008. FRS_SYSVOL_SECTION,
  4009. KEY_ALL_ACCESS,
  4010. &HKey);
  4011. if (!WIN_SUCCESS(WStatus)) {
  4012. goto cleanup;
  4013. }
  4014. #if 0
  4015. // Don't bother committing the "Delete sysvol" registry values because,
  4016. // after the reboot, the computer will not have sufficient rights to
  4017. // delete the sysvol from the Ds. Hence the call to DsDeleteCommit()
  4018. // below. Leave the code as a place holder for now.
  4019. //
  4020. // Set the value that indicates the sysvol subkeys are valid
  4021. //
  4022. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  4023. ErrorCallBack,
  4024. FRS_SYSVOL_SECTION,
  4025. HKey,
  4026. SYSVOL_INFO_IS_COMMITTED,
  4027. REG_DWORD,
  4028. (PCHAR)&SysVolInfoIsCommitted,
  4029. sizeof(SysVolInfoIsCommitted));
  4030. if (!WIN_SUCCESS(WStatus)) {
  4031. goto cleanup;
  4032. }
  4033. #endif 0
  4034. //
  4035. // Service starts automatically at startup
  4036. //
  4037. if (!ChangeServiceConfig(ServiceHandle,
  4038. SERVICE_NO_CHANGE,
  4039. SERVICE_AUTO_START,
  4040. SERVICE_NO_CHANGE,
  4041. NULL,
  4042. NULL,
  4043. NULL,
  4044. NULL,
  4045. NULL,
  4046. NULL,
  4047. NtFrsApi_ServiceLongName)) {
  4048. WStatus = GetLastError();
  4049. NTFRSAPI_DBG_PRINT1("Commit demotion: no auto %d\n", WStatus);
  4050. }
  4051. //
  4052. // Insure access to the netlogon\parameters key
  4053. //
  4054. NTFRSAPI_DBG_PRINT0("Commit Demotion: Netlogon registry\n");
  4055. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  4056. NULL,
  4057. NETLOGON_SECTION,
  4058. KEY_ALL_ACCESS,
  4059. &HNetKey);
  4060. if (WIN_SUCCESS(WStatus)) {
  4061. //
  4062. // Tell NetLogon to stop sharing the sysvol
  4063. //
  4064. SysvolReady = 0;
  4065. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  4066. NULL,
  4067. NETLOGON_SECTION,
  4068. HNetKey,
  4069. SYSVOL_READY,
  4070. REG_DWORD,
  4071. (PCHAR)&SysvolReady,
  4072. sizeof(DWORD));
  4073. }
  4074. WStatus = ERROR_SUCCESS;
  4075. //
  4076. // Delete our DS objects in some other DS. We cannot delete
  4077. // the objects from the DS on this DC because this DS is
  4078. // going away. We cannot delete the objects in another DS
  4079. // after rebooting because, as a member server, we no longer
  4080. // have permissions to delete our objects.
  4081. //
  4082. // The service will, however, continue to retry the deletes
  4083. // just in case this computer comes up as a DC after the
  4084. // demotion completed. BSTS.
  4085. //
  4086. DsDeleteCommit();
  4087. //
  4088. // Success
  4089. //
  4090. NtFrsApi_State = NTFRSAPI_COMMITTED;
  4091. WStatus = ERROR_SUCCESS;
  4092. cleanup:;
  4093. } except (EXCEPTION_EXECUTE_HANDLER) {
  4094. //
  4095. // Exception (may be RPC)
  4096. //
  4097. GET_EXCEPTION_CODE(WStatus);
  4098. }
  4099. //
  4100. // Clean up any handles, events, memory, ...
  4101. //
  4102. try {
  4103. if (ServiceHandle) {
  4104. CloseServiceHandle(ServiceHandle);
  4105. }
  4106. if (HANDLE_IS_VALID(HKey)) {
  4107. RegCloseKey(HKey);
  4108. }
  4109. if (HANDLE_IS_VALID(HNetKey)) {
  4110. RegCloseKey(HNetKey);
  4111. }
  4112. if (RpcHandle) {
  4113. WStatus1 = RpcBindingFree(&RpcHandle);
  4114. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4115. }
  4116. } except (EXCEPTION_EXECUTE_HANDLER) {
  4117. //
  4118. // Exception (may be RPC)
  4119. //
  4120. GET_EXCEPTION_CODE(WStatus);
  4121. }
  4122. done:;
  4123. } finally {
  4124. //
  4125. // Release locks
  4126. //
  4127. LeaveCriticalSection(&NtFrsApi_GlobalLock);
  4128. if (AbnormalTermination()) {
  4129. WStatus = FRS_ERR_INTERNAL_API;
  4130. }
  4131. }
  4132. NTFRSAPI_DBG_PRINT1("Commit demotion done: %d\n", WStatus);
  4133. NTFRSAPI_DBG_UNPREPARE();
  4134. return WStatus;
  4135. }
  4136. DWORD
  4137. WINAPI
  4138. NtFrsApi_Set_DsPollingIntervalW(
  4139. IN PWCHAR ComputerName, OPTIONAL
  4140. IN ULONG UseShortInterval,
  4141. IN ULONG LongInterval,
  4142. IN ULONG ShortInterval
  4143. )
  4144. /*++
  4145. Routine Description:
  4146. The NtFrs service polls the DS occasionally for configuration changes.
  4147. This API alters the polling interval and, if the service is not
  4148. in the middle of a polling cycle, forces the service to begin a
  4149. polling cycle.
  4150. The service uses the long interval by default. The short interval
  4151. is used after the ds configuration has been successfully
  4152. retrieved and the service is now verifying that the configuration
  4153. is not in flux. This API can be used to force the service to use
  4154. the short interval until a stable configuration has been retrieved.
  4155. After which, the service reverts back to the long interval.
  4156. The default values for ShortInterval and LongInterval can be
  4157. changed by setting the parameters to a non-zero value. If zero,
  4158. the current values remain unchanged and a polling cycle is initiated.
  4159. Arguments:
  4160. ComputerName - Poke the service on this computer. The computer
  4161. name can be any RPC-bindable name. Usually, the
  4162. NetBIOS or DNS name works just fine. The NetBIOS
  4163. name can be found with GetComputerName() or
  4164. hostname. The DNS name can be found with
  4165. gethostbyname() or ipconfig /all. If NULL, the
  4166. service on this computer is contacted. The service
  4167. is contacted using Secure RPC.
  4168. UseShortInterval - If non-zero, the service switches to the short
  4169. interval until a stable configuration is retrieved
  4170. from the DS or another call to this API is made.
  4171. Otherwise, the service uses the long interval.
  4172. LongInterval - Minutes between polls of the DS. The value must fall
  4173. between NTFRSAPI_MIN_INTERVAL and NTFRSAPI_MAX_INTERVAL,
  4174. inclusive. If 0, the interval is unchanged.
  4175. ShortInterval - Minutes between polls of the DS. The value must fall
  4176. between NTFRSAPI_MIN_INTERVAL and NTFRSAPI_MAX_INTERVAL,
  4177. inclusive. If 0, the interval is unchanged.
  4178. Return Value:
  4179. Win32 Status
  4180. --*/
  4181. {
  4182. DWORD WStatus, WStatus1;
  4183. DWORD AuthWStatus;
  4184. DWORD NoAuthWStatus;
  4185. handle_t AuthHandle = NULL;
  4186. handle_t NoAuthHandle = NULL;
  4187. try {
  4188. //
  4189. // Check LongInterval
  4190. //
  4191. if (LongInterval &&
  4192. (LongInterval < NTFRSAPI_MIN_INTERVAL ||
  4193. LongInterval > NTFRSAPI_MAX_INTERVAL)) {
  4194. WStatus = ERROR_INVALID_PARAMETER;
  4195. goto CLEANUP;
  4196. }
  4197. //
  4198. // Check ShortInterval
  4199. //
  4200. if (ShortInterval &&
  4201. (ShortInterval < NTFRSAPI_MIN_INTERVAL ||
  4202. ShortInterval > NTFRSAPI_MAX_INTERVAL)) {
  4203. WStatus = ERROR_INVALID_PARAMETER;
  4204. goto CLEANUP;
  4205. }
  4206. //
  4207. // Bind to the service with and without authentication
  4208. //
  4209. AuthWStatus = NtFrsApi_BindWithAuth(ComputerName, NULL, &AuthHandle);
  4210. NoAuthWStatus = NtFrsApi_Bind(ComputerName, NULL, &NoAuthHandle);
  4211. //
  4212. // Send Authenticated RPC request to service
  4213. //
  4214. if (HANDLE_IS_VALID(AuthHandle)) {
  4215. try {
  4216. WStatus = NtFrsApi_Rpc_Set_DsPollingIntervalW(AuthHandle,
  4217. UseShortInterval,
  4218. LongInterval,
  4219. ShortInterval);
  4220. } except (EXCEPTION_EXECUTE_HANDLER) {
  4221. GET_EXCEPTION_CODE(WStatus);
  4222. }
  4223. } else {
  4224. WStatus = ERROR_ACCESS_DENIED;
  4225. }
  4226. if (WStatus == ERROR_ACCESS_DENIED) {
  4227. //
  4228. // Send Unauthenticated RPC request to service
  4229. //
  4230. if (HANDLE_IS_VALID(NoAuthHandle)) {
  4231. try {
  4232. WStatus = NtFrsApi_Rpc_Set_DsPollingIntervalW(NoAuthHandle,
  4233. UseShortInterval,
  4234. LongInterval,
  4235. ShortInterval);
  4236. } except (EXCEPTION_EXECUTE_HANDLER) {
  4237. GET_EXCEPTION_CODE(WStatus);
  4238. }
  4239. } else {
  4240. WStatus = NoAuthWStatus;
  4241. }
  4242. }
  4243. if (!WIN_SUCCESS(WStatus)) {
  4244. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  4245. goto CLEANUP;
  4246. }
  4247. CLEANUP:;
  4248. } except (EXCEPTION_EXECUTE_HANDLER) {
  4249. //
  4250. // Exception (may be RPC)
  4251. //
  4252. GET_EXCEPTION_CODE(WStatus);
  4253. }
  4254. //
  4255. // Clean up any handles, events, memory, ...
  4256. //
  4257. try {
  4258. //
  4259. // Unbind
  4260. //
  4261. if (AuthHandle) {
  4262. WStatus1 = RpcBindingFree(&AuthHandle);
  4263. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4264. }
  4265. if (NoAuthHandle) {
  4266. WStatus1 = RpcBindingFree(&NoAuthHandle);
  4267. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4268. }
  4269. } except (EXCEPTION_EXECUTE_HANDLER) {
  4270. //
  4271. // Exception (may be RPC)
  4272. //
  4273. GET_EXCEPTION_CODE(WStatus);
  4274. }
  4275. return WStatus;
  4276. }
  4277. DWORD
  4278. WINAPI
  4279. NtFrsApi_Get_DsPollingIntervalW(
  4280. IN PWCHAR ComputerName, OPTIONAL
  4281. OUT ULONG *Interval,
  4282. OUT ULONG *LongInterval,
  4283. OUT ULONG *ShortInterval
  4284. )
  4285. /*++
  4286. Routine Description:
  4287. The NtFrs service polls the DS occasionally for configuration changes.
  4288. This API returns the values the service uses for polling intervals.
  4289. The service uses the long interval by default. The short interval
  4290. is used after the ds configuration has been successfully
  4291. retrieved and the service is now verifying that the configuration
  4292. is not in flux. The short interval is also used if the
  4293. NtFrsApi_Set_DsPollingIntervalW() is used to force usage of the short
  4294. interval until a stable configuration has been retrieved. After which,
  4295. the service reverts back to the long interval.
  4296. The value returned in Interval is the polling interval currently in
  4297. use.
  4298. Arguments:
  4299. ComputerName - Poke the service on this computer. The computer
  4300. name can be any RPC-bindable name. Usually, the
  4301. NetBIOS or DNS name works just fine. The NetBIOS
  4302. name can be found with GetComputerName() or
  4303. hostname. The DNS name can be found with
  4304. gethostbyname() or ipconfig /all. If NULL, the
  4305. service on this computer is contacted. The service
  4306. is contacted using Secure RPC.
  4307. Interval - The current polling interval in minutes.
  4308. LongInterval - The long interval in minutes.
  4309. ShortInterval - The short interval in minutes.
  4310. Return Value:
  4311. Win32 Status
  4312. --*/
  4313. {
  4314. #undef NTFRSAPI_MODULE
  4315. #define NTFRSAPI_MODULE "NtFrsApi_Get_DsPollingIntervalW:"
  4316. DWORD WStatus, WStatus1;
  4317. DWORD NoAuthWStatus;
  4318. DWORD AuthWStatus;
  4319. handle_t AuthHandle = NULL;
  4320. handle_t NoAuthHandle = NULL;
  4321. try {
  4322. //
  4323. // Bind to the service with and without authentication
  4324. //
  4325. AuthWStatus = NtFrsApi_BindWithAuth(ComputerName, NULL, &AuthHandle);
  4326. NoAuthWStatus = NtFrsApi_Bind(ComputerName, NULL, &NoAuthHandle);
  4327. //
  4328. // Send Authenticated RPC request to service
  4329. //
  4330. if (HANDLE_IS_VALID(AuthHandle)) {
  4331. try {
  4332. WStatus = NtFrsApi_Rpc_Get_DsPollingIntervalW(AuthHandle,
  4333. Interval,
  4334. LongInterval,
  4335. ShortInterval);
  4336. } except (EXCEPTION_EXECUTE_HANDLER) {
  4337. GET_EXCEPTION_CODE(WStatus);
  4338. }
  4339. } else {
  4340. WStatus = ERROR_ACCESS_DENIED;
  4341. }
  4342. if (WStatus == ERROR_ACCESS_DENIED || WStatus == RPC_S_CALL_FAILED_DNE) {
  4343. //
  4344. // Send Unauthenticated RPC request to service
  4345. //
  4346. if (HANDLE_IS_VALID(NoAuthHandle)) {
  4347. try {
  4348. WStatus = NtFrsApi_Rpc_Get_DsPollingIntervalW(NoAuthHandle,
  4349. Interval,
  4350. LongInterval,
  4351. ShortInterval);
  4352. } except (EXCEPTION_EXECUTE_HANDLER) {
  4353. GET_EXCEPTION_CODE(WStatus);
  4354. }
  4355. } else {
  4356. WStatus = NoAuthWStatus;
  4357. }
  4358. }
  4359. if (!WIN_SUCCESS(WStatus)) {
  4360. WStatus = NtFrsApi_Fix_Comm_WStatus(WStatus);
  4361. goto CLEANUP;
  4362. }
  4363. CLEANUP:;
  4364. } except (EXCEPTION_EXECUTE_HANDLER) {
  4365. //
  4366. // Exception (may be RPC)
  4367. //
  4368. GET_EXCEPTION_CODE(WStatus);
  4369. }
  4370. //
  4371. // Clean up any handles, events, memory, ...
  4372. //
  4373. try {
  4374. //
  4375. // Unbind
  4376. //
  4377. if (AuthHandle) {
  4378. WStatus1 = RpcBindingFree(&AuthHandle);
  4379. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4380. }
  4381. if (NoAuthHandle) {
  4382. WStatus1 = RpcBindingFree(&NoAuthHandle);
  4383. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4384. }
  4385. } except (EXCEPTION_EXECUTE_HANDLER) {
  4386. //
  4387. // Exception (may be RPC)
  4388. //
  4389. GET_EXCEPTION_CODE(WStatus);
  4390. }
  4391. return WStatus;
  4392. }
  4393. DWORD
  4394. WINAPI
  4395. NtFrsApi_InfoW(
  4396. IN PWCHAR ComputerName, OPTIONAL
  4397. IN ULONG TypeOfInfo,
  4398. IN ULONG SizeInChars,
  4399. IN OUT PVOID *NtFrsApiInfo
  4400. )
  4401. /*++
  4402. Routine Description:
  4403. Return a buffer full of the requested information. The information
  4404. can be extracted from the buffer with NtFrsApi_InfoLineW().
  4405. *NtFrsApiInfo should be NULL on the first call. On subsequent calls,
  4406. *NtFrsApiInfo will be filled in with more data if any is present.
  4407. Otherwise, *NtFrsApiInfo is set to NULL and the memory is freed.
  4408. The SizeInChars is a suggested size; the actual memory usage
  4409. may be different. The function chooses the memory usage if
  4410. SizeInChars is 0.
  4411. The format of the returned information can change without notice.
  4412. Arguments:
  4413. ComputerName - Poke the service on this computer. The computer
  4414. name can be any RPC-bindable name. Usually, the
  4415. NetBIOS or DNS name works just fine. The NetBIOS
  4416. name can be found with GetComputerName() or
  4417. hostname. The DNS name can be found with
  4418. gethostbyname() or ipconfig /all. If NULL, the
  4419. service on this computer is contacted. The service
  4420. is contacted using Secure RPC.
  4421. TypeOfInfo - See the constants beginning with NTFRSAPI_INFO_
  4422. in ntfrsapi.h.
  4423. SizeInChars - Suggested memory usage; actual may be different.
  4424. 0 == Function chooses memory usage
  4425. NtFrsApiInfo - Opaque. Parse with NtFrsApi_InfoLineW().
  4426. Free with NtFrsApi_InfoFreeW();
  4427. Return Value:
  4428. Win32 Status
  4429. --*/
  4430. {
  4431. #undef NTFRSAPI_MODULE
  4432. #define NTFRSAPI_MODULE "NtFrsApi_InfoW:"
  4433. DWORD WStatus, WStatus1;
  4434. DWORD NoAuthWStatus;
  4435. DWORD AuthWStatus;
  4436. PNTFRSAPI_INFO Info = NULL;
  4437. handle_t AuthHandle = NULL;
  4438. handle_t NoAuthHandle = NULL;
  4439. try {
  4440. //
  4441. // Adjust memory usage
  4442. //
  4443. if (!SizeInChars) {
  4444. SizeInChars = NTFRSAPI_DEFAULT_INFO_SIZE;
  4445. } else if (SizeInChars < NTFRSAPI_MINIMUM_INFO_SIZE) {
  4446. SizeInChars = NTFRSAPI_MINIMUM_INFO_SIZE;
  4447. }
  4448. //
  4449. // Check params
  4450. //
  4451. Info = *NtFrsApiInfo;
  4452. if (Info) {
  4453. TypeOfInfo = Info->TypeOfInfo;
  4454. }
  4455. //
  4456. // Allocate a large text buffer
  4457. //
  4458. if (Info) {
  4459. if (!NtFrsApi_InfoMoreW(Info)) {
  4460. NtFrsApi_InfoFreeW(NtFrsApiInfo);
  4461. WStatus = ERROR_SUCCESS;
  4462. goto CLEANUP;
  4463. }
  4464. Info->CharsToSkip = Info->TotalChars;
  4465. Info->Flags = 0;
  4466. Info->OffsetToFree = (ULONG)(Info->Lines - (PCHAR)Info);
  4467. Info->OffsetToLines = Info->OffsetToFree;
  4468. } else {
  4469. Info = NtFrsApi_Alloc(SizeInChars);
  4470. Info->Major = NTFRS_MAJOR;
  4471. Info->Minor = NTFRS_MINOR;
  4472. Info->SizeInChars = SizeInChars;
  4473. Info->OffsetToFree = (ULONG)(Info->Lines - (PCHAR)Info);
  4474. Info->OffsetToLines = Info->OffsetToFree;
  4475. Info->TypeOfInfo = TypeOfInfo;
  4476. *NtFrsApiInfo = Info;
  4477. }
  4478. //
  4479. // Caller only wants info on the api; deliver it
  4480. //
  4481. if (TypeOfInfo == NTFRSAPI_INFO_TYPE_VERSION) {
  4482. NTFRSAPI_IPRINT0(Info, "NtFrsApi Version Information\n");
  4483. NTFRSAPI_IPRINT1(Info, " NtFrsApi Major : %d\n", NTFRS_MAJOR);
  4484. NTFRSAPI_IPRINT1(Info, " NtFrsApi Minor : %d\n", NTFRS_MINOR);
  4485. // NTFRSAPI_IPRINT1(Info, " NtFrsApi Module : %hs\n", NtFrsApi_Module);
  4486. NTFRSAPI_IPRINT2(Info, " NtFrsApi Compiled on: %s %s\n",
  4487. NtFrsApi_Date, NtFrsApi_Time);
  4488. #if NTFRS_TEST
  4489. NTFRSAPI_IPRINT0(Info, " NTFRS_TEST Enabled\n");
  4490. #else NTFRS_TEST
  4491. NTFRSAPI_IPRINT0(Info, " NTFRS_TEST Disabled\n");
  4492. #endif NTFRS_TEST
  4493. }
  4494. //
  4495. // Bind to the service with and without authentication
  4496. //
  4497. AuthWStatus = NtFrsApi_BindWithAuth(ComputerName, NULL, &AuthHandle);
  4498. if (!WIN_SUCCESS(AuthWStatus)) {
  4499. NTFRSAPI_IPRINT3(Info, "ERROR - Cannot bind w/authentication to computer, %ws; %08x (%d)\n",
  4500. ComputerName, AuthWStatus, AuthWStatus);
  4501. }
  4502. NoAuthWStatus = NtFrsApi_Bind(ComputerName, NULL, &NoAuthHandle);
  4503. if (!WIN_SUCCESS(NoAuthWStatus)) {
  4504. NTFRSAPI_IPRINT3(Info, "ERROR - Cannot bind w/o authentication to computer, %ws; %08x (%d)\n",
  4505. ComputerName, NoAuthWStatus, NoAuthWStatus);
  4506. }
  4507. //
  4508. // Send Authenticated RPC request to service
  4509. //
  4510. if (HANDLE_IS_VALID(AuthHandle)) {
  4511. try {
  4512. WStatus = NtFrsApi_Rpc_InfoW(AuthHandle,
  4513. Info->SizeInChars,
  4514. (PBYTE)Info);
  4515. } except (EXCEPTION_EXECUTE_HANDLER) {
  4516. GET_EXCEPTION_CODE(WStatus);
  4517. }
  4518. } else {
  4519. WStatus = ERROR_ACCESS_DENIED;
  4520. }
  4521. if (WStatus == ERROR_ACCESS_DENIED ||
  4522. WStatus == RPC_S_CALL_FAILED_DNE) {
  4523. //
  4524. // Send Unauthenticated RPC request to service
  4525. //
  4526. if (HANDLE_IS_VALID(NoAuthHandle)) {
  4527. try {
  4528. WStatus = NtFrsApi_Rpc_InfoW(NoAuthHandle,
  4529. Info->SizeInChars,
  4530. (PBYTE)Info);
  4531. } except (EXCEPTION_EXECUTE_HANDLER) {
  4532. GET_EXCEPTION_CODE(WStatus);
  4533. }
  4534. } else {
  4535. WStatus = NoAuthWStatus;
  4536. }
  4537. }
  4538. if (!WIN_SUCCESS(WStatus)) {
  4539. NTFRSAPI_IPRINT3(Info, "ERROR - Cannot RPC to computer, %ws; %08x (%d)\n",
  4540. ComputerName, WStatus, WStatus);
  4541. WStatus = ERROR_SUCCESS;
  4542. goto CLEANUP;
  4543. }
  4544. WStatus = ERROR_SUCCESS;
  4545. CLEANUP:;
  4546. } except (EXCEPTION_EXECUTE_HANDLER) {
  4547. //
  4548. // Exception (may be RPC)
  4549. //
  4550. GET_EXCEPTION_CODE(WStatus);
  4551. }
  4552. //
  4553. // Clean up any handles, events, memory, ...
  4554. //
  4555. try {
  4556. //
  4557. // Unbind
  4558. //
  4559. if (AuthHandle) {
  4560. WStatus1 = RpcBindingFree(&AuthHandle);
  4561. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4562. }
  4563. if (NoAuthHandle) {
  4564. WStatus1 = RpcBindingFree(&NoAuthHandle);
  4565. NtFrsApiCheckRpcError(WStatus1, "RpcBindingFree");
  4566. }
  4567. if (!WIN_SUCCESS(WStatus)) {
  4568. FREE(*NtFrsApiInfo);
  4569. }
  4570. } except (EXCEPTION_EXECUTE_HANDLER) {
  4571. //
  4572. // Exception (may be RPC)
  4573. //
  4574. GET_EXCEPTION_CODE(WStatus);
  4575. }
  4576. return WStatus;
  4577. }
  4578. DWORD
  4579. WINAPI
  4580. NtFrsApi_InfoLineW(
  4581. IN PNTFRSAPI_INFO NtFrsApiInfo,
  4582. IN OUT PVOID *InOutLine
  4583. )
  4584. /*++
  4585. Routine Description:
  4586. Extract the wchar lines of information from NtFrsApiInformation.
  4587. Returns the address of the next L'\0' terminated line of information.
  4588. NULL if none.
  4589. Arguments:
  4590. NtFrsApiInfo - Opaque. Returned by NtFrsApi_InfoW().
  4591. Parse with NtFrsApi_InfoLineW().
  4592. Free with NtFrsApi_InfoFreeW().
  4593. Return Value:
  4594. Win32 Status
  4595. --*/
  4596. {
  4597. #undef NTFRSAPI_MODULE
  4598. #define NTFRSAPI_MODULE "NtFrsApi_InfoLineW:"
  4599. DWORD WStatus;
  4600. PCHAR NextLine;
  4601. PCHAR FirstLine;
  4602. PCHAR FreeLine;
  4603. try {
  4604. //
  4605. // Check input params
  4606. //
  4607. if (!InOutLine) {
  4608. WStatus = ERROR_INVALID_PARAMETER;
  4609. goto cleanup;
  4610. }
  4611. if (!NtFrsApiInfo) {
  4612. *InOutLine = NULL;
  4613. WStatus = ERROR_INVALID_PARAMETER;
  4614. goto cleanup;
  4615. }
  4616. NextLine = *InOutLine;
  4617. FirstLine = ((PCHAR)NtFrsApiInfo) + NtFrsApiInfo->OffsetToLines;
  4618. FreeLine = ((PCHAR)NtFrsApiInfo) + NtFrsApiInfo->OffsetToFree;
  4619. if (!NextLine) {
  4620. NextLine = FirstLine;
  4621. } else {
  4622. if (NextLine < FirstLine) {
  4623. *InOutLine = NULL;
  4624. WStatus = ERROR_INVALID_PARAMETER;
  4625. goto cleanup;
  4626. }
  4627. if (NextLine < FreeLine) {
  4628. NextLine += strlen(NextLine) + 1;
  4629. }
  4630. }
  4631. if (NextLine >= FreeLine) {
  4632. *InOutLine = NULL;
  4633. } else {
  4634. *InOutLine = NextLine;
  4635. }
  4636. WStatus = ERROR_SUCCESS;
  4637. cleanup:;
  4638. } except (EXCEPTION_EXECUTE_HANDLER) {
  4639. //
  4640. // Exception
  4641. //
  4642. GET_EXCEPTION_CODE(WStatus);
  4643. }
  4644. //
  4645. // Clean up any handles, events, memory, ...
  4646. //
  4647. try {
  4648. } except (EXCEPTION_EXECUTE_HANDLER) {
  4649. //
  4650. // Exception
  4651. //
  4652. GET_EXCEPTION_CODE(WStatus);
  4653. }
  4654. return WStatus;
  4655. }
  4656. DWORD
  4657. WINAPI
  4658. NtFrsApi_InfoFreeW(
  4659. IN PVOID *NtFrsApiInfo
  4660. )
  4661. /*++
  4662. Routine Description:
  4663. Free the information buffer allocated by NtFrsApi_InfoW();
  4664. Arguments:
  4665. NtFrsApiInfo - Opaque. Returned by NtFrsApi_InfoW().
  4666. Parse with NtFrsApi_InfoLineW().
  4667. Free with NtFrsApi_InfoFreeW().
  4668. Return Value:
  4669. Win32 Status
  4670. --*/
  4671. {
  4672. #undef NTFRSAPI_MODULE
  4673. #define NTFRSAPI_MODULE "NtFrsApi_InfoFreeW:"
  4674. DWORD WStatus;
  4675. try {
  4676. FREE(*NtFrsApiInfo);
  4677. WStatus = ERROR_SUCCESS;
  4678. } except (EXCEPTION_EXECUTE_HANDLER) {
  4679. //
  4680. // Exception
  4681. //
  4682. GET_EXCEPTION_CODE(WStatus);
  4683. }
  4684. //
  4685. // Clean up any handles, events, memory, ...
  4686. //
  4687. try {
  4688. } except (EXCEPTION_EXECUTE_HANDLER) {
  4689. //
  4690. // Exception
  4691. //
  4692. GET_EXCEPTION_CODE(WStatus);
  4693. }
  4694. return WStatus;
  4695. }
  4696. BOOL
  4697. WINAPI
  4698. NtFrsApi_InfoMoreW(
  4699. IN PNTFRSAPI_INFO NtFrsApiInfo
  4700. )
  4701. /*++
  4702. Routine Description:
  4703. All of the information may not have fit in the buffer. The additional
  4704. information can be fetched by calling NtFrsApi_InfoW() again with the
  4705. same NtFrsApiInfo struct. NtFrsApi_InfoW() will return NULL in
  4706. NtFrsApiInfo if there is no more information.
  4707. However, the information returned in subsequent calls to _InfoW() may be
  4708. out of sync with the previous information. If the user requires a
  4709. coherent information set, then the information buffer should be freed
  4710. with NtFrsApi_InfoFreeW() and another call made to NtFrsApi_InfoW()
  4711. with an increased SizeInChars. Repeat the procedure until
  4712. NtFrsApi_InfoMoreW() returns FALSE.
  4713. Arguments:
  4714. NtFrsApiInfo - Opaque. Returned by NtFrsApi_InfoW().
  4715. Parse with NtFrsApi_InfoLineW().
  4716. Free with NtFrsApi_InfoFreeW().
  4717. Return Value:
  4718. TRUE - The information buffer does *NOT* contain all of the info.
  4719. FALSE - The information buffer does contain all of the info.
  4720. --*/
  4721. {
  4722. #undef NTFRSAPI_MODULE
  4723. #define NTFRSAPI_MODULE "NtFrsApi_InfoMoreW:"
  4724. DWORD WStatus;
  4725. BOOL BStatus = FALSE;
  4726. try {
  4727. //
  4728. // If we have an info buffer
  4729. // and the info buffer is full
  4730. // and there was at least one line in the info buffer
  4731. // then there is more info.
  4732. //
  4733. if (NtFrsApiInfo &&
  4734. FlagOn(NtFrsApiInfo->Flags, NTFRSAPI_INFO_FLAGS_FULL) &&
  4735. NtFrsApiInfo->OffsetToLines != NtFrsApiInfo->OffsetToFree) {
  4736. BStatus = TRUE;
  4737. }
  4738. } except (EXCEPTION_EXECUTE_HANDLER) {
  4739. //
  4740. // Exception
  4741. //
  4742. GET_EXCEPTION_CODE(WStatus);
  4743. }
  4744. //
  4745. // Clean up any handles, events, memory, ...
  4746. //
  4747. try {
  4748. } except (EXCEPTION_EXECUTE_HANDLER) {
  4749. //
  4750. // Exception
  4751. //
  4752. GET_EXCEPTION_CODE(WStatus);
  4753. }
  4754. return BStatus;
  4755. }
  4756. DWORD
  4757. WINAPI
  4758. NtFrsApiStopServiceForRestore(
  4759. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  4760. IN DWORD BurFlags
  4761. )
  4762. /*++
  4763. Routine Description:
  4764. Old code left over from Version 1.0 of the Backup/restore api.
  4765. Used as subroutine for Version 3.0.
  4766. Stop the service and update the registry.
  4767. Arguments:
  4768. ErrorCallBack - Ignored if NULL.
  4769. Address of function provided by the caller. If
  4770. not NULL, this function calls back with a formatted
  4771. error message and the error code that caused the
  4772. error.
  4773. BurFlags - Callers Backup/Restore flags
  4774. Return Value:
  4775. Win32 Status
  4776. --*/
  4777. {
  4778. #undef NTFRSAPI_MODULE
  4779. #define NTFRSAPI_MODULE "NtFrsApiStopServiceForRestore:"
  4780. DWORD WStatus;
  4781. DWORD SizeInChars;
  4782. DWORD CharsNeeded;
  4783. DWORD Hint;
  4784. BOOL IsAutoStart;
  4785. BOOL IsRunning;
  4786. DWORD BurStopDisposition;
  4787. PWCHAR ObjectName = NULL;
  4788. HKEY HBurMvKey = 0;
  4789. HKEY HBurStopKey = 0;
  4790. SERVICE_STATUS ServiceStatus;
  4791. SC_HANDLE ServiceHandle = NULL;
  4792. QUERY_SERVICE_CONFIG *ServiceConfig = NULL;
  4793. try {
  4794. //
  4795. // STOP THE SERVICE
  4796. //
  4797. //
  4798. // Open the service
  4799. //
  4800. WStatus = NtFrsApi_GetServiceHandle(ErrorCallBack, &ServiceHandle);
  4801. if (!WIN_SUCCESS(WStatus)) {
  4802. goto CLEANUP;
  4803. }
  4804. //
  4805. // Get Service config
  4806. //
  4807. SizeInChars = 1024;
  4808. QUERY_SERVICE_AGAIN:
  4809. ServiceConfig = NtFrsApi_Alloc(SizeInChars);
  4810. if (!QueryServiceConfig(ServiceHandle, ServiceConfig, SizeInChars, &CharsNeeded)) {
  4811. WStatus = GetLastError();
  4812. if (WIN_BUF_TOO_SMALL(WStatus) && CharsNeeded > SizeInChars) {
  4813. SizeInChars = CharsNeeded;
  4814. FREE(ServiceConfig);
  4815. goto QUERY_SERVICE_AGAIN;
  4816. }
  4817. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  4818. }
  4819. IsAutoStart = (ServiceConfig->dwStartType == SERVICE_AUTO_START);
  4820. //
  4821. // Get Service status
  4822. //
  4823. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  4824. WStatus = GetLastError();
  4825. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  4826. }
  4827. IsRunning = (ServiceStatus.dwCurrentState == SERVICE_RUNNING);
  4828. Hint = ServiceStatus.dwWaitHint;
  4829. //
  4830. // Stop the service
  4831. //
  4832. if (IsRunning) {
  4833. if (!ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) {
  4834. WStatus = GetLastError();
  4835. if (WStatus == ERROR_SERVICE_REQUEST_TIMEOUT) {
  4836. WStatus = ERROR_SUCCESS;
  4837. if (!ControlService(ServiceHandle,
  4838. SERVICE_CONTROL_STOP,
  4839. &ServiceStatus)) {
  4840. WStatus = GetLastError();
  4841. if (WStatus == ERROR_SERVICE_NOT_ACTIVE) {
  4842. WStatus = ERROR_SUCCESS;
  4843. }
  4844. }
  4845. }
  4846. }
  4847. WStatus = NtFrsApi_WaitForService(ServiceHandle,
  4848. Hint,
  4849. SERVICE_STOP_PENDING,
  4850. SERVICE_STOPPED);
  4851. if (!WIN_SUCCESS(WStatus)) {
  4852. WStatus = FRS_ERR_STOPPING_SERVICE;
  4853. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  4854. }
  4855. }
  4856. //
  4857. // Update the registry
  4858. //
  4859. //
  4860. // Open the ntfrs parameters\backup/restore\Startup section
  4861. //
  4862. WStatus = RegCreateKey(HKEY_LOCAL_MACHINE,
  4863. FRS_BACKUP_RESTORE_MV_SECTION,
  4864. &HBurMvKey);
  4865. if (WIN_SUCCESS(WStatus)) {
  4866. RegCloseKey(HBurMvKey);
  4867. HBurMvKey = 0;
  4868. }
  4869. //
  4870. // Re-open using reduced access
  4871. //
  4872. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  4873. ErrorCallBack,
  4874. FRS_BACKUP_RESTORE_MV_SECTION,
  4875. KEY_SET_VALUE,
  4876. &HBurMvKey);
  4877. if (!WIN_SUCCESS(WStatus)) {
  4878. goto CLEANUP;
  4879. }
  4880. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  4881. ErrorCallBack,
  4882. FRS_BACKUP_RESTORE_MV_SECTION,
  4883. HBurMvKey,
  4884. FRS_VALUE_BURFLAGS,
  4885. REG_DWORD,
  4886. (PCHAR)&BurFlags,
  4887. sizeof(DWORD));
  4888. if (!WIN_SUCCESS(WStatus)) {
  4889. goto CLEANUP;
  4890. }
  4891. //
  4892. // Create the volatile key to prevent the service from starting
  4893. //
  4894. WStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  4895. FRS_BACKUP_RESTORE_STOP_SECTION,
  4896. 0,
  4897. NULL,
  4898. REG_OPTION_VOLATILE,
  4899. KEY_ALL_ACCESS,
  4900. NULL,
  4901. &HBurStopKey,
  4902. &BurStopDisposition);
  4903. if (!WIN_SUCCESS(WStatus)) {
  4904. NtFrsApi_CallBackOnWStatus(ErrorCallBack, FRS_BACKUP_RESTORE_STOP_SECTION, WStatus);
  4905. //
  4906. // Ignore errors
  4907. //
  4908. WStatus = ERROR_SUCCESS;
  4909. }
  4910. //
  4911. // SUCCESS
  4912. //
  4913. WStatus = ERROR_SUCCESS;
  4914. CLEANUP:;
  4915. } except (EXCEPTION_EXECUTE_HANDLER) {
  4916. GET_EXCEPTION_CODE(WStatus);
  4917. }
  4918. //
  4919. // Clean up any handles, events, memory, ...
  4920. //
  4921. try {
  4922. if (ServiceHandle) {
  4923. CloseServiceHandle(ServiceHandle);
  4924. }
  4925. if (HANDLE_IS_VALID(HBurMvKey)) {
  4926. RegCloseKey(HBurMvKey);
  4927. }
  4928. if (HANDLE_IS_VALID(HBurStopKey)) {
  4929. RegCloseKey(HBurStopKey);
  4930. }
  4931. FREE(ServiceConfig);
  4932. FREE(ObjectName);
  4933. } except (EXCEPTION_EXECUTE_HANDLER) {
  4934. GET_EXCEPTION_CODE(WStatus);
  4935. }
  4936. return WStatus;
  4937. }
  4938. DWORD
  4939. WINAPI
  4940. NtFrsApiStartServiceAfterRestore(
  4941. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  4942. )
  4943. /*++
  4944. Routine Description:
  4945. Old code from Version 1.0 of the Backup/Restore API. Used
  4946. as subroutine in Version 3.0.
  4947. Restart the service after a restore has completed.
  4948. Arguments:
  4949. ErrorCallBack - Ignored if NULL.
  4950. Address of function provided by the caller. If
  4951. not NULL, this function calls back with a formatted
  4952. error message and the error code that caused the
  4953. error.
  4954. Return Value:
  4955. Win32 Status
  4956. --*/
  4957. {
  4958. #undef NTFRSAPI_MODULE
  4959. #define NTFRSAPI_MODULE "NtFrsApiStartServiceAfterRestore:"
  4960. DWORD WStatus;
  4961. DWORD SizeInChars;
  4962. DWORD CharsNeeded;
  4963. DWORD Hint;
  4964. BOOL IsAutoStart;
  4965. SERVICE_STATUS ServiceStatus;
  4966. SC_HANDLE ServiceHandle = NULL;
  4967. QUERY_SERVICE_CONFIG *ServiceConfig = NULL;
  4968. try {
  4969. //
  4970. // Delete the volatile key that prevents the service from starting
  4971. //
  4972. WStatus = NtFrsApiDeleteKey(NTFRSAPI_MODULE,
  4973. NULL,
  4974. NULL,
  4975. HKEY_LOCAL_MACHINE,
  4976. FRS_BACKUP_RESTORE_STOP_SECTION);
  4977. if (!WIN_SUCCESS(WStatus)) {
  4978. //
  4979. // Ignore errors
  4980. //
  4981. WStatus = ERROR_SUCCESS;
  4982. }
  4983. //
  4984. // START THE SERVICE
  4985. //
  4986. //
  4987. // Open the service
  4988. //
  4989. WStatus = NtFrsApi_GetServiceHandle(ErrorCallBack, &ServiceHandle);
  4990. if (!WIN_SUCCESS(WStatus)) {
  4991. goto CLEANUP;
  4992. }
  4993. //
  4994. // Get Service config
  4995. //
  4996. SizeInChars = 1024;
  4997. QUERY_SERVICE_AGAIN:
  4998. ServiceConfig = NtFrsApi_Alloc(SizeInChars);
  4999. if (!QueryServiceConfig(ServiceHandle, ServiceConfig, SizeInChars, &CharsNeeded)) {
  5000. WStatus = GetLastError();
  5001. if (WIN_BUF_TOO_SMALL(WStatus) && CharsNeeded > SizeInChars) {
  5002. SizeInChars = CharsNeeded;
  5003. FREE(ServiceConfig);
  5004. goto QUERY_SERVICE_AGAIN;
  5005. }
  5006. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  5007. }
  5008. IsAutoStart = (ServiceConfig->dwStartType == SERVICE_AUTO_START);
  5009. //
  5010. // Get Service status
  5011. //
  5012. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  5013. WStatus = GetLastError();
  5014. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  5015. }
  5016. Hint = ServiceStatus.dwWaitHint;
  5017. //
  5018. // Restart the service
  5019. //
  5020. if (IsAutoStart) {
  5021. if (!StartService(ServiceHandle, 0, NULL)) {
  5022. WStatus = GetLastError();
  5023. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  5024. }
  5025. WStatus = NtFrsApi_WaitForService(ServiceHandle,
  5026. Hint,
  5027. SERVICE_START_PENDING,
  5028. SERVICE_RUNNING);
  5029. if (!WIN_SUCCESS(WStatus)) {
  5030. WStatus = FRS_ERR_STARTING_SERVICE;
  5031. CLEANUP_CB(ErrorCallBack, SERVICE_NAME, WStatus, CLEANUP);
  5032. }
  5033. }
  5034. //
  5035. // SUCCESS
  5036. //
  5037. WStatus = ERROR_SUCCESS;
  5038. CLEANUP:;
  5039. } except (EXCEPTION_EXECUTE_HANDLER) {
  5040. GET_EXCEPTION_CODE(WStatus);
  5041. }
  5042. //
  5043. // Clean up any handles, events, memory, ...
  5044. //
  5045. try {
  5046. if (ServiceHandle) {
  5047. CloseServiceHandle(ServiceHandle);
  5048. }
  5049. FREE(ServiceConfig);
  5050. } except (EXCEPTION_EXECUTE_HANDLER) {
  5051. GET_EXCEPTION_CODE(WStatus);
  5052. }
  5053. return WStatus;
  5054. }
  5055. DWORD
  5056. WINAPI
  5057. NtFrsApiMoveCumulativeSets(
  5058. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG) OPTIONAL
  5059. )
  5060. /*++
  5061. Routine Description:
  5062. Move the cumulative replica sets currently in the registry into the
  5063. backup/restore key that will (might) be moved into the restored
  5064. registry at the end of restore. This is to maintain as much state
  5065. as possible about un-deleted replica sets. An old registry may
  5066. lack info about new sets that will appear once the current restored
  5067. DS is updated from its partners.
  5068. Arguments:
  5069. ErrorCallBack - Ignored if NULL. Otherwise, call on error.
  5070. Return Value:
  5071. Win32 Status
  5072. --*/
  5073. {
  5074. #undef NTFRSAPI_MODULE
  5075. #define NTFRSAPI_MODULE "NtFrsApiMoveCumulativeSets:"
  5076. DWORD WStatus;
  5077. DWORD KeyIdx;
  5078. DWORD RegType;
  5079. DWORD RegBytes;
  5080. PWCHAR CumuPath = NULL;
  5081. PWCHAR BurCumuPath = NULL;
  5082. PWCHAR ObjectName = NULL;
  5083. HKEY HCumusKey = 0;
  5084. HKEY HCumuKey = 0;
  5085. HKEY HBurCumusKey = 0;
  5086. HKEY HBurCumuKey = 0;
  5087. WCHAR RegBuf[MAX_PATH + 1];
  5088. //
  5089. // Open CUMULATIVE REPLICA SETS
  5090. //
  5091. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  5092. ErrorCallBack,
  5093. FRS_CUMULATIVE_SETS_SECTION,
  5094. KEY_ENUMERATE_SUB_KEYS,
  5095. &HCumusKey);
  5096. if (!WIN_SUCCESS(WStatus)) {
  5097. goto CLEANUP;
  5098. }
  5099. //
  5100. // Open BACKUP RESTORE CUMULATIVE REPLICA SETS
  5101. //
  5102. WStatus = RegCreateKey(HKEY_LOCAL_MACHINE,
  5103. FRS_BACKUP_RESTORE_MV_CUMULATIVE_SETS_SECTION,
  5104. &HBurCumusKey);
  5105. if (WIN_SUCCESS(WStatus)) {
  5106. RegCloseKey(HBurCumusKey);
  5107. HBurCumusKey = 0;
  5108. }
  5109. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  5110. ErrorCallBack,
  5111. FRS_BACKUP_RESTORE_MV_CUMULATIVE_SETS_SECTION,
  5112. KEY_CREATE_SUB_KEY,
  5113. &HBurCumusKey);
  5114. if (!WIN_SUCCESS(WStatus)) {
  5115. goto CLEANUP;
  5116. }
  5117. // Enumerate the Cumulative Replica Sets
  5118. //
  5119. KeyIdx = 0;
  5120. do {
  5121. WStatus = RegEnumKey(HCumusKey, KeyIdx, RegBuf, MAX_PATH + 1);
  5122. if (WStatus == ERROR_NO_MORE_ITEMS) {
  5123. break;
  5124. }
  5125. CLEANUP_CB(ErrorCallBack, FRS_CUMULATIVE_SETS_SECTION, WStatus, CLEANUP);
  5126. //
  5127. // Full path of both the source and target key
  5128. //
  5129. CumuPath = NtFrsApi_Cats(FRS_CUMULATIVE_SETS_SECTION, L"\\", RegBuf);
  5130. BurCumuPath = NtFrsApi_Cats(FRS_BACKUP_RESTORE_MV_CUMULATIVE_SETS_SECTION,
  5131. L"\\",
  5132. RegBuf);
  5133. //
  5134. // Open the cumulative replica set
  5135. //
  5136. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  5137. ErrorCallBack,
  5138. CumuPath,
  5139. KEY_READ,
  5140. &HCumuKey);
  5141. if (!WIN_SUCCESS(WStatus)) {
  5142. goto CLEANUP_DURING_LOOP;
  5143. }
  5144. //
  5145. // Create the backup restore cumulative replica set
  5146. //
  5147. WStatus = RegCreateKey(HKEY_LOCAL_MACHINE, BurCumuPath, &HBurCumuKey);
  5148. CLEANUP_CB(ErrorCallBack, BurCumuPath, WStatus, CLEANUP_DURING_LOOP);
  5149. CLEANUP_DURING_LOOP:
  5150. if (HANDLE_IS_VALID(HCumuKey)) {
  5151. RegCloseKey(HCumuKey);
  5152. HCumuKey = 0;
  5153. }
  5154. if (HANDLE_IS_VALID(HBurCumuKey)) {
  5155. RegCloseKey(HBurCumuKey);
  5156. HBurCumuKey = 0;
  5157. }
  5158. FREE(CumuPath);
  5159. FREE(BurCumuPath);
  5160. FREE(ObjectName);
  5161. ++KeyIdx;
  5162. } while (TRUE);
  5163. //
  5164. // SUCCESS
  5165. //
  5166. WStatus = ERROR_SUCCESS;
  5167. CLEANUP:
  5168. //
  5169. // Clean up any handles, events, memory, ...
  5170. //
  5171. if (HANDLE_IS_VALID(HCumuKey)) {
  5172. RegCloseKey(HCumuKey);
  5173. }
  5174. if (HANDLE_IS_VALID(HBurCumuKey)) {
  5175. RegCloseKey(HBurCumuKey);
  5176. }
  5177. if (HANDLE_IS_VALID(HCumusKey)) {
  5178. RegCloseKey(HCumusKey);
  5179. }
  5180. if (HANDLE_IS_VALID(HBurCumusKey)) {
  5181. RegCloseKey(HBurCumusKey);
  5182. }
  5183. FREE(CumuPath);
  5184. FREE(BurCumuPath);
  5185. FREE(ObjectName);
  5186. return WStatus;
  5187. }
  5188. typedef struct _NTFRSAPI_BUR_SET NTFRSAPI_BUR_SET, *PNTFRSAPI_BUR_SET;
  5189. struct _NTFRSAPI_BUR_SET {
  5190. PNTFRSAPI_BUR_SET BurSetNext; // next in list of sets
  5191. PWCHAR BurSetGuid; // member guid is also name of registry key
  5192. PWCHAR BurSetRoot; // root path
  5193. PWCHAR BurSetStage; // stage path
  5194. PWCHAR BurSetType; // type of set (domain, enterprise, ...)
  5195. };
  5196. //
  5197. // Context generated by NtFrsApiInitializeBackupRestore() and freed by
  5198. // NtFrsApiDestroyBackupRestore(). Used for all other function calls.
  5199. //
  5200. typedef struct _NTFRSAPI_BUR_CONTEXT {
  5201. DWORD BurFlags; // from caller
  5202. PNTFRSAPI_BUR_SET BurSets; // See NtFrsApiGetBackupRestoreSets
  5203. DWORD BurFiltersSizeInBytes; // Size of BurFilters
  5204. PWCHAR BurFilters; // From registry
  5205. BOOL HaveBurSemaphore; // Holding the semaphore
  5206. HANDLE BurSemaphore; // This is a single thread API
  5207. DWORD (*ErrorCallBack)(IN PWCHAR, IN ULONG); // from caller
  5208. } NTFRSAPI_BUR_CONTEXT, *PNTFRSAPI_BUR_CONTEXT;
  5209. VOID
  5210. WINAPI
  5211. NtFrsApiFreeBurSets(
  5212. IN PNTFRSAPI_BUR_SET *BurSets
  5213. )
  5214. /*++
  5215. Routine Description:
  5216. Free the linked list of BurSets and set *BurSets to NULL.
  5217. Arguments:
  5218. BurSets - Linked list of BurSets
  5219. Return Value:
  5220. Win32 Status
  5221. --*/
  5222. {
  5223. #undef NTFRSAPI_MODULE
  5224. #define NTFRSAPI_MODULE "NtFrsApiFreeBurSets:"
  5225. PNTFRSAPI_BUR_SET LocalBurSet;
  5226. while (LocalBurSet = *BurSets) {
  5227. *BurSets = LocalBurSet->BurSetNext;
  5228. FREE(LocalBurSet->BurSetGuid);
  5229. FREE(LocalBurSet->BurSetRoot);
  5230. FREE(LocalBurSet->BurSetStage);
  5231. FREE(LocalBurSet->BurSetType);
  5232. FREE(LocalBurSet);
  5233. }
  5234. }
  5235. DWORD
  5236. WINAPI
  5237. NtFrsApiInitializeBackupRestore(
  5238. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  5239. IN DWORD BurFlags,
  5240. OUT PVOID *BurContext
  5241. )
  5242. /*++
  5243. Routine Description:
  5244. Called once in the lifetime of a backup/restore process. Must be
  5245. matched with a subsequent call to NtFrsApiDestroyBackupRestore().
  5246. Prepare the system for the backup or restore specified by BurFlags.
  5247. Currently, the following combinations are supported:
  5248. ASR - Automated System Recovery
  5249. NTFRSAPI_BUR_FLAGS_RESTORE |
  5250. NTFRSAPI_BUR_FLAGS_SYSTEM |
  5251. NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES |
  5252. NTFRSAPI_BUR_FLAGS_PRIMARY or NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE
  5253. DSR - Distributed Services Restore (all sets)
  5254. NTFRSAPI_BUR_FLAGS_RESTORE |
  5255. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY |
  5256. NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES |
  5257. NTFRSAPI_BUR_FLAGS_PRIMARY or NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE
  5258. DSR - Distributed Services Restore (just the sysvol)
  5259. NTFRSAPI_BUR_FLAGS_RESTORE |
  5260. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY
  5261. (may be followed by subsequent calls to NtFrsApiRestoringDirectory())
  5262. Normal Restore - System is up and running; just restoring files
  5263. NTFRSAPI_BUR_FLAGS_RESTORE |
  5264. NTFRSAPI_BUR_FLAGS_NORMAL |
  5265. NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES |
  5266. NTFRSAPI_BUR_FLAGS_AUTHORITATIVE
  5267. Normal Backup
  5268. NTFRSAPI_BUR_FLAGS_BACKUP |
  5269. NTFRSAPI_BUR_FLAGS_NORMAL
  5270. Arguments:
  5271. ErrorCallBack - Ignored if NULL.
  5272. Address of function provided by the caller. If
  5273. not NULL, this function calls back with a formatted
  5274. error message and the error code that caused the
  5275. error.
  5276. BurFlags - See above for the supported combinations
  5277. BurContext - Opaque context for this process
  5278. Return Value:
  5279. Win32 Status
  5280. --*/
  5281. {
  5282. #undef NTFRSAPI_MODULE
  5283. #define NTFRSAPI_MODULE "NtFrsApiInitializeBackupRestore:"
  5284. DWORD WStatus;
  5285. DWORD WaitStatus;
  5286. PNTFRSAPI_BUR_CONTEXT LocalBurContext = NULL;
  5287. try {
  5288. //
  5289. // VERIFY THE PARAMETERS
  5290. //
  5291. //
  5292. // Must be one of backup or restore
  5293. //
  5294. if (!(BurFlags & (NTFRSAPI_BUR_FLAGS_BACKUP |
  5295. NTFRSAPI_BUR_FLAGS_RESTORE))) {
  5296. WStatus = ERROR_INVALID_PARAMETER;
  5297. CLEANUP_CB(ErrorCallBack, L"BurFlags ~(BACKUP|RESTORE)", WStatus, CLEANUP);
  5298. }
  5299. //
  5300. // RESTORE
  5301. //
  5302. if (BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) {
  5303. //
  5304. // Can't be both backup and restore
  5305. //
  5306. if (BurFlags & NTFRSAPI_BUR_FLAGS_BACKUP) {
  5307. WStatus = ERROR_INVALID_PARAMETER;
  5308. CLEANUP_CB(ErrorCallBack, L"BurFlags (RESTORE|BACKUP)", WStatus, CLEANUP);
  5309. }
  5310. //
  5311. // Restore supports a few flags
  5312. //
  5313. if (BurFlags & ~NTFRSAPI_BUR_FLAGS_SUPPORTED_RESTORE) {
  5314. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5315. CLEANUP_CB(ErrorCallBack, L"BurFlags ONE OR MORE FLAGS", WStatus, CLEANUP);
  5316. }
  5317. //
  5318. // Select only one type of restore
  5319. //
  5320. switch (BurFlags & NTFRSAPI_BUR_FLAGS_TYPES_OF_RESTORE) {
  5321. //
  5322. // Authoritative
  5323. //
  5324. case NTFRSAPI_BUR_FLAGS_AUTHORITATIVE:
  5325. if (BurFlags & (NTFRSAPI_BUR_FLAGS_SYSTEM |
  5326. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5327. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5328. CLEANUP_CB(ErrorCallBack, L"BurFlags (SYSTEM | ACTIVE | AUTHORITATIVE)", WStatus, CLEANUP);
  5329. }
  5330. break;
  5331. //
  5332. // Non-Authoritative
  5333. //
  5334. case NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE:
  5335. //
  5336. // NORMAL
  5337. //
  5338. if (BurFlags & NTFRSAPI_BUR_FLAGS_NORMAL) {
  5339. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5340. CLEANUP_CB(ErrorCallBack, L"BurFlags (NORMAL | NON-AUTHORITATIVE)", WStatus, CLEANUP);
  5341. }
  5342. //
  5343. // _ACTIVE_DIRECTORY and not ALL
  5344. //
  5345. if ((BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY) &&
  5346. (!(BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES))) {
  5347. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5348. CLEANUP_CB(ErrorCallBack, L"BurFlags (ACTIVE DIRECTORY | NON-AUTHORITATIVE w/o ALL)", WStatus, CLEANUP);
  5349. }
  5350. break;
  5351. //
  5352. // Primary
  5353. //
  5354. case NTFRSAPI_BUR_FLAGS_PRIMARY:
  5355. if (BurFlags & NTFRSAPI_BUR_FLAGS_NORMAL) {
  5356. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5357. CLEANUP_CB(ErrorCallBack, L"BurFlags (NORMAL | PRIMARY)", WStatus, CLEANUP);
  5358. }
  5359. //
  5360. // _ACTIVE_DIRECTORY and not ALL
  5361. //
  5362. if ((BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY) &&
  5363. (!(BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES))) {
  5364. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5365. CLEANUP_CB(ErrorCallBack, L"BurFlags (ACTIVE DIRECTORY | PRIMARY w/o ALL)", WStatus, CLEANUP);
  5366. }
  5367. break;
  5368. //
  5369. // None
  5370. //
  5371. case NTFRSAPI_BUR_FLAGS_NONE:
  5372. if ((BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES) ||
  5373. !(BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5374. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5375. CLEANUP_CB(ErrorCallBack, L"BurFlags TOO FEW TYPES", WStatus, CLEANUP);
  5376. }
  5377. break;
  5378. //
  5379. // More than one or none
  5380. //
  5381. default:
  5382. WStatus = ERROR_INVALID_PARAMETER;
  5383. CLEANUP_CB(ErrorCallBack, L"BurFlags TOO MANY TYPES", WStatus, CLEANUP);
  5384. }
  5385. //
  5386. // Select only one mode of restore
  5387. //
  5388. switch (BurFlags & NTFRSAPI_BUR_FLAGS_MODES_OF_RESTORE) {
  5389. //
  5390. // System
  5391. //
  5392. case NTFRSAPI_BUR_FLAGS_SYSTEM:
  5393. if (!(BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES)) {
  5394. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5395. CLEANUP_CB(ErrorCallBack, L"BurFlags SYSTEM without ALL", WStatus, CLEANUP);
  5396. }
  5397. break;
  5398. //
  5399. // Active Directory
  5400. //
  5401. case NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY:
  5402. #if 0
  5403. if (!(BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES)) {
  5404. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5405. CLEANUP_CB(ErrorCallBack, L"BurFlags ACTIVE DIRECTORY without ALL", WStatus, CLEANUP);
  5406. }
  5407. #endif 0
  5408. break;
  5409. //
  5410. // Normal
  5411. //
  5412. case NTFRSAPI_BUR_FLAGS_NORMAL:
  5413. if (!(BurFlags & NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES)) {
  5414. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5415. CLEANUP_CB(ErrorCallBack, L"BurFlags NORMAL without ALL", WStatus, CLEANUP);
  5416. }
  5417. break;
  5418. //
  5419. // More than one
  5420. //
  5421. default:
  5422. WStatus = ERROR_INVALID_PARAMETER;
  5423. CLEANUP_CB(ErrorCallBack, L"BurFlags TOO MANY/FEW MODES", WStatus, CLEANUP);
  5424. }
  5425. //
  5426. // BACKUP
  5427. //
  5428. } else {
  5429. //
  5430. // Backup supports a subset of BurFlags
  5431. //
  5432. if (BurFlags & ~NTFRSAPI_BUR_FLAGS_SUPPORTED_BACKUP) {
  5433. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5434. CLEANUP_CB(ErrorCallBack, L"BurFlags unsupported BACKUP Flag(s)", WStatus, CLEANUP);
  5435. }
  5436. //
  5437. // Normal must be set
  5438. //
  5439. if (!(BurFlags & NTFRSAPI_BUR_FLAGS_NORMAL)) {
  5440. WStatus = ERROR_CALL_NOT_IMPLEMENTED;
  5441. CLEANUP_CB(ErrorCallBack, L"BurFlags BACKUP without NORMAL", WStatus, CLEANUP);
  5442. }
  5443. }
  5444. //
  5445. // Must have someplace to return the context
  5446. //
  5447. if (!BurContext) {
  5448. WStatus = ERROR_INVALID_PARAMETER;
  5449. CLEANUP_CB(ErrorCallBack, L"BurContext", WStatus, CLEANUP);
  5450. }
  5451. //
  5452. // No context, yet
  5453. //
  5454. *BurContext = NULL;
  5455. //
  5456. // Allocate a context
  5457. //
  5458. LocalBurContext = NtFrsApi_Alloc(sizeof(NTFRSAPI_BUR_CONTEXT));
  5459. LocalBurContext->ErrorCallBack = ErrorCallBack,
  5460. LocalBurContext->BurFlags = BurFlags;
  5461. //
  5462. // Only one backup/restore is allowed at a time
  5463. //
  5464. LocalBurContext->BurSemaphore = CreateSemaphore(NULL,
  5465. 1,
  5466. 1,
  5467. NTFRS_BACKUP_RESTORE_SEMAPHORE);
  5468. if (!HANDLE_IS_VALID(LocalBurContext->BurSemaphore)) {
  5469. LocalBurContext->BurSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS,
  5470. FALSE,
  5471. NTFRS_BACKUP_RESTORE_SEMAPHORE);
  5472. }
  5473. if (!HANDLE_IS_VALID(LocalBurContext->BurSemaphore)) {
  5474. WStatus = GetLastError();
  5475. CLEANUP_CB(ErrorCallBack, NTFRS_BACKUP_RESTORE_SEMAPHORE, WStatus, CLEANUP);
  5476. }
  5477. WaitStatus = WaitForSingleObject(LocalBurContext->BurSemaphore, 1 * 1000);
  5478. if (WaitStatus != WAIT_OBJECT_0) {
  5479. if (WaitStatus == WAIT_TIMEOUT) {
  5480. WStatus = ERROR_BUSY;
  5481. } else if (WaitStatus == WAIT_ABANDONED){
  5482. WStatus = ERROR_SEM_OWNER_DIED;
  5483. } else {
  5484. WStatus = GetLastError();
  5485. }
  5486. CLEANUP_CB(ErrorCallBack, NTFRS_BACKUP_RESTORE_SEMAPHORE, WStatus, CLEANUP);
  5487. }
  5488. LocalBurContext->HaveBurSemaphore = TRUE;
  5489. //
  5490. // Stop the service and set the appropriate registry value
  5491. //
  5492. // THE RESTORE IS EFFECTIVELY COMMITTED AT THIS TIME!
  5493. //
  5494. if (BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE &&
  5495. !(BurFlags & NTFRSAPI_BUR_FLAGS_NORMAL)) {
  5496. WStatus = NtFrsApiStopServiceForRestore(ErrorCallBack, BurFlags);
  5497. if (!WIN_SUCCESS(WStatus)) {
  5498. goto CLEANUP;
  5499. }
  5500. //
  5501. // Save the current set of replica sets
  5502. //
  5503. WStatus = NtFrsApiMoveCumulativeSets(NULL);
  5504. if (!WIN_SUCCESS(WStatus)) {
  5505. // Ignore error; caller may not care
  5506. WStatus = ERROR_SUCCESS;
  5507. }
  5508. }
  5509. //
  5510. // SUCCESS
  5511. //
  5512. WStatus = ERROR_SUCCESS;
  5513. *BurContext = LocalBurContext;
  5514. LocalBurContext = NULL;
  5515. CLEANUP:;
  5516. } except (EXCEPTION_EXECUTE_HANDLER) {
  5517. GET_EXCEPTION_CODE(WStatus);
  5518. }
  5519. //
  5520. // Clean up any handles, events, memory, ...
  5521. //
  5522. try {
  5523. //
  5524. // Release semaphore
  5525. //
  5526. if (LocalBurContext && HANDLE_IS_VALID(LocalBurContext->BurSemaphore)) {
  5527. if (LocalBurContext->HaveBurSemaphore) {
  5528. ReleaseSemaphore(LocalBurContext->BurSemaphore, 1, NULL);
  5529. }
  5530. CloseHandle(LocalBurContext->BurSemaphore);
  5531. }
  5532. //
  5533. // Context
  5534. //
  5535. if (LocalBurContext) {
  5536. NtFrsApiFreeBurSets(&LocalBurContext->BurSets);
  5537. LocalBurContext->BurFiltersSizeInBytes = 0;
  5538. FREE(LocalBurContext->BurFilters);
  5539. FREE(LocalBurContext);
  5540. }
  5541. } except (EXCEPTION_EXECUTE_HANDLER) {
  5542. GET_EXCEPTION_CODE(WStatus);
  5543. }
  5544. return WStatus;
  5545. }
  5546. DWORD
  5547. WINAPI
  5548. NtFrsApiRestoringDirectory(
  5549. IN PVOID BurContext,
  5550. IN PVOID BurSet,
  5551. IN DWORD BurFlags
  5552. )
  5553. /*++
  5554. Routine Description:
  5555. The backup/restore application is about to restore the directory
  5556. specified by BurSet (See NtFrsApiEnumBackupRestoreSets()). Matched
  5557. with a later call to NtFrsApiFinishedRestoringDirectory().
  5558. This call is supported only if NtFrsApiInitializeBackupRestore()
  5559. were called with the flags:
  5560. NTFRSAPI_BUR_FLAGS_RESTORE |
  5561. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY
  5562. BurFlags can be NTFRSAPI_BUR_FLAGS_PRIMARY or
  5563. NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE and overrides any value
  5564. specified in the call to NtFrsApiInitializeBackupRestore().
  5565. Arguments:
  5566. BurContext - Opaque context from NtFrsApiInitializeBackupRestore()
  5567. BurSet - Opaque set from NtFrsApiEnumBackupRestoreSets();
  5568. BurFlags - See above for the supported combinations
  5569. Return Value:
  5570. Win32 Status
  5571. --*/
  5572. {
  5573. #undef NTFRSAPI_MODULE
  5574. #define NTFRSAPI_MODULE "NtFrsApiRestoringDirectory:"
  5575. DWORD WStatus;
  5576. DWORD WaitStatus;
  5577. PNTFRSAPI_BUR_SET LocalBurSet;
  5578. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  5579. HKEY HBurSetKey = 0;
  5580. PWCHAR BurSetPath = NULL;
  5581. PWCHAR ObjectName = NULL;
  5582. try {
  5583. //
  5584. // VERIFY THE PARAMETERS
  5585. //
  5586. if (!LocalBurContext) {
  5587. WStatus = ERROR_INVALID_PARAMETER;
  5588. goto CLEANUP;
  5589. }
  5590. //
  5591. // Must be one of primary or nonauth
  5592. //
  5593. if (!(BurFlags & (NTFRSAPI_BUR_FLAGS_PRIMARY |
  5594. NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE))) {
  5595. WStatus = ERROR_INVALID_PARAMETER;
  5596. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurFlags not (PRIMARY|NON-AUTH)", WStatus, CLEANUP);
  5597. }
  5598. //
  5599. // Can only be one of primary or nonauth
  5600. //
  5601. if (BurFlags & ~(NTFRSAPI_BUR_FLAGS_PRIMARY |
  5602. NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE)) {
  5603. WStatus = ERROR_INVALID_PARAMETER;
  5604. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurFlags not just (PRIMARY|NON-AUTH)", WStatus, CLEANUP);
  5605. }
  5606. //
  5607. // Must be a restore context
  5608. //
  5609. if (!(LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE)) {
  5610. WStatus = ERROR_INVALID_PARAMETER;
  5611. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurContext not RESTORE", WStatus, CLEANUP);
  5612. }
  5613. //
  5614. // Must be an active directory context
  5615. //
  5616. if (!(LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5617. WStatus = ERROR_INVALID_PARAMETER;
  5618. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurContext not ACTIVE_DIRECTORY", WStatus, CLEANUP);
  5619. }
  5620. //
  5621. // Re-locate the correct BurSet
  5622. //
  5623. for (LocalBurSet = LocalBurContext->BurSets;
  5624. LocalBurSet && (LocalBurSet != BurSet);
  5625. LocalBurSet = LocalBurSet->BurSetNext) {
  5626. }
  5627. if (!LocalBurSet) {
  5628. WStatus = ERROR_NOT_FOUND;
  5629. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurSet", WStatus, CLEANUP);
  5630. }
  5631. //
  5632. // Corrupted BurSet
  5633. //
  5634. if (!LocalBurSet->BurSetGuid) {
  5635. WStatus = ERROR_NOT_FOUND;
  5636. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurSet Id", WStatus, CLEANUP);
  5637. }
  5638. //
  5639. // Full path to registry key
  5640. //
  5641. BurSetPath = NtFrsApi_Cats(FRS_BACKUP_RESTORE_MV_SETS_SECTION,
  5642. L"\\",
  5643. LocalBurSet->BurSetGuid);
  5644. WStatus = RegCreateKey(HKEY_LOCAL_MACHINE, BurSetPath, &HBurSetKey);
  5645. if (!WIN_SUCCESS(WStatus)) {
  5646. CLEANUP_CB(LocalBurContext->ErrorCallBack, BurSetPath, WStatus, CLEANUP);
  5647. }
  5648. //
  5649. // Retain _RESTORE and _ACTIVE_DIRECTORY in the registry value
  5650. //
  5651. BurFlags |= LocalBurContext->BurFlags &
  5652. (NTFRSAPI_BUR_FLAGS_RESTORE |
  5653. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY);
  5654. WStatus = NtFrsApiSetValueEx(NTFRSAPI_MODULE,
  5655. LocalBurContext->ErrorCallBack,
  5656. BurSetPath,
  5657. HBurSetKey,
  5658. FRS_VALUE_BURFLAGS,
  5659. REG_DWORD,
  5660. (PCHAR)&BurFlags,
  5661. sizeof(DWORD));
  5662. if (!WIN_SUCCESS(WStatus)) {
  5663. goto CLEANUP;
  5664. }
  5665. //
  5666. // SUCCESS
  5667. //
  5668. WStatus = ERROR_SUCCESS;
  5669. CLEANUP:;
  5670. } except (EXCEPTION_EXECUTE_HANDLER) {
  5671. GET_EXCEPTION_CODE(WStatus);
  5672. }
  5673. //
  5674. // Clean up any handles, events, memory, ...
  5675. //
  5676. try {
  5677. if (HANDLE_IS_VALID(HBurSetKey)) {
  5678. RegCloseKey(HBurSetKey);
  5679. }
  5680. FREE(BurSetPath);
  5681. FREE(ObjectName);
  5682. } except (EXCEPTION_EXECUTE_HANDLER) {
  5683. GET_EXCEPTION_CODE(WStatus);
  5684. }
  5685. return WStatus;
  5686. }
  5687. DWORD
  5688. WINAPI
  5689. NtFrsApiFinishedRestoringDirectory(
  5690. IN PVOID BurContext,
  5691. IN PVOID BurSet,
  5692. IN DWORD BurFlags
  5693. )
  5694. /*++
  5695. Routine Description:
  5696. Finished restoring directory for BurSet. Matched by a previous call
  5697. to NtFrsApiRestoringDirectory().
  5698. This call is supported only if NtFrsApiInitializeBackupRestore()
  5699. were called with the flags:
  5700. NTFRSAPI_BUR_FLAGS_RESTORE |
  5701. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY
  5702. BurFlags must be NTFRSAPI_BUR_FLAGS_NONE.
  5703. Arguments:
  5704. BurContext - Opaque context from NtFrsApiInitializeBackupRestore()
  5705. BurSet - Opaque set from NtFrsApiEnumBackupRestoreSets();
  5706. BurFlags - See above for the supported combinations
  5707. Return Value:
  5708. Win32 Status
  5709. --*/
  5710. {
  5711. #undef NTFRSAPI_MODULE
  5712. #define NTFRSAPI_MODULE "NtFrsApiRestoringDirectory:"
  5713. DWORD WStatus;
  5714. DWORD WaitStatus;
  5715. PNTFRSAPI_BUR_SET LocalBurSet;
  5716. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  5717. try {
  5718. //
  5719. // VERIFY THE PARAMETERS
  5720. //
  5721. if (!LocalBurContext) {
  5722. WStatus = ERROR_INVALID_PARAMETER;
  5723. goto CLEANUP;
  5724. }
  5725. //
  5726. // Must be one of primary or nonauth
  5727. //
  5728. if (BurFlags != NTFRSAPI_BUR_FLAGS_NONE) {
  5729. WStatus = ERROR_INVALID_PARAMETER;
  5730. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurFlags not NONE", WStatus, CLEANUP);
  5731. }
  5732. //
  5733. // Must be restore context
  5734. //
  5735. if (!(LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE)) {
  5736. WStatus = ERROR_INVALID_PARAMETER;
  5737. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurContext not RESTORE", WStatus, CLEANUP);
  5738. }
  5739. //
  5740. // Must be active directory context
  5741. //
  5742. if (!(LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5743. WStatus = ERROR_INVALID_PARAMETER;
  5744. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurContext not ACTIVE_DIRECTORY", WStatus, CLEANUP);
  5745. }
  5746. //
  5747. // Re-locate BurSet
  5748. //
  5749. for (LocalBurSet = LocalBurContext->BurSets;
  5750. LocalBurSet && (LocalBurSet != BurSet);
  5751. LocalBurSet = LocalBurSet->BurSetNext) {
  5752. }
  5753. if (!LocalBurSet) {
  5754. WStatus = ERROR_NOT_FOUND;
  5755. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurSet", WStatus, CLEANUP);
  5756. }
  5757. //
  5758. // SUCCESS
  5759. //
  5760. WStatus = ERROR_SUCCESS;
  5761. CLEANUP:;
  5762. } except (EXCEPTION_EXECUTE_HANDLER) {
  5763. GET_EXCEPTION_CODE(WStatus);
  5764. }
  5765. //
  5766. // Clean up any handles, events, memory, ...
  5767. //
  5768. try {
  5769. } except (EXCEPTION_EXECUTE_HANDLER) {
  5770. GET_EXCEPTION_CODE(WStatus);
  5771. }
  5772. return WStatus;
  5773. }
  5774. DWORD
  5775. WINAPI
  5776. NtFrsApiDestroyBackupRestore(
  5777. IN PVOID *BurContext,
  5778. IN DWORD BurFlags,
  5779. OUT HKEY *HKey,
  5780. IN OUT DWORD *KeyPathSizeInBytes,
  5781. OUT PWCHAR KeyPath
  5782. )
  5783. /*++
  5784. Routine Description:
  5785. Called once in the lifetime of a backup/restore process. Must be
  5786. matched with a previous call to NtFrsApiInitializeBackupRestore().
  5787. If NtFrsApiInitializeBackupRestore() was called with:
  5788. NTFRSAPI_BUR_FLAGS_RESTORE |
  5789. NTFRSAPI_BUR_FLAGS_SYSTEM or NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY
  5790. then BurFlags may be set to one of:
  5791. NTFRSAPI_BUR_FLAGS_NONE - Do not restart the service. The key
  5792. specified by (HKey, KeyPath) must be moved into the final
  5793. registry.
  5794. NTFRSAPI_BUR_FLAGS_RESTART - Restart the service. HKey,
  5795. KeyPathSizeInBytes, and KeyPath must be NULL.
  5796. If NtFrsApiInitializeBackupRestore() was not called the above flags,
  5797. then BurFlags must be NTFRSAPI_BUR_FLAGS_NONE and HKey, KeyPathSizeInBytes,
  5798. and KeyPath must be NULL.
  5799. Arguments:
  5800. BurContext - Returned by previous call to
  5801. NtFrsApiInitializeBackupRestore().
  5802. BurFlags - Backup/Restore Flags. See Routine Description.
  5803. HKey - Address of a HKEY for that will be set to
  5804. HKEY_LOCAL_MACHINE, ...
  5805. NULL if BurContext is not for a System or
  5806. Active Directory restore or Restart is set.
  5807. KeyPathSizeInBytes - Address of of a DWORD specifying the size of
  5808. KeyPath. Set to the actual number of bytes
  5809. needed by KeyPath. ERROR_INSUFFICIENT_BUFFER
  5810. is returned if the size of KeyPath is too small.
  5811. NULL if BurContext is not for a System or
  5812. Active Directory restore or Restart is set.
  5813. KeyPath - Buffer to receive the path of the registry key.
  5814. NULL if BurContext is not for a System or
  5815. Active Directory restore or Restart is set.
  5816. Return Value:
  5817. Win32 Status
  5818. --*/
  5819. {
  5820. #undef NTFRSAPI_MODULE
  5821. #define NTFRSAPI_MODULE "NtFrsApiDestroyBackupRestore:"
  5822. DWORD WStatus;
  5823. DWORD KeyLen;
  5824. PNTFRSAPI_BUR_SET LocalBurSet;
  5825. PNTFRSAPI_BUR_CONTEXT LocalBurContext;
  5826. try {
  5827. //
  5828. // VERIFY THE PARAMETERS
  5829. //
  5830. //
  5831. // Context
  5832. //
  5833. if (!BurContext || !*BurContext) {
  5834. WStatus = ERROR_INVALID_PARAMETER;
  5835. goto CLEANUP;
  5836. }
  5837. LocalBurContext = *BurContext;
  5838. //
  5839. // Restart is the only supported flag
  5840. //
  5841. if (LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) {
  5842. //
  5843. // RESTORE
  5844. //
  5845. if (BurFlags & ~NTFRSAPI_BUR_FLAGS_RESTART) {
  5846. WStatus = ERROR_INVALID_PARAMETER;
  5847. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurFlags TOO MANY FLAGS", WStatus, CLEANUP);
  5848. }
  5849. if (LocalBurContext->BurFlags & (NTFRSAPI_BUR_FLAGS_SYSTEM |
  5850. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5851. if (BurFlags & NTFRSAPI_BUR_FLAGS_RESTART) {
  5852. if (HKey || KeyPathSizeInBytes || KeyPath) {
  5853. WStatus = ERROR_INVALID_PARAMETER;
  5854. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"HKey, KeyPathSizeInBytes, KeyPath", WStatus, CLEANUP);
  5855. }
  5856. } else {
  5857. if (!HKey || !KeyPathSizeInBytes || !KeyPath) {
  5858. WStatus = ERROR_INVALID_PARAMETER;
  5859. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"No HKey, KeyPathSizeInBytes, KeyPath", WStatus, CLEANUP);
  5860. }
  5861. KeyLen = sizeof(WCHAR) *
  5862. (wcslen(FRS_BACKUP_RESTORE_MV_SECTION) + 1);
  5863. if (KeyLen > *KeyPathSizeInBytes) {
  5864. *KeyPathSizeInBytes = KeyLen;
  5865. WStatus = ERROR_INSUFFICIENT_BUFFER;
  5866. goto CLEANUP;
  5867. }
  5868. }
  5869. } else if (HKey || KeyPathSizeInBytes || KeyPath) {
  5870. WStatus = ERROR_INVALID_PARAMETER;
  5871. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"HKey, KeyPathSizeInBytes, KeyPath", WStatus, CLEANUP);
  5872. }
  5873. //
  5874. // BACKUP
  5875. //
  5876. } else {
  5877. if (BurFlags) {
  5878. WStatus = ERROR_INVALID_PARAMETER;
  5879. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"BurFlags TOO MANY FLAGS", WStatus, CLEANUP);
  5880. }
  5881. if (HKey || KeyPathSizeInBytes || KeyPath) {
  5882. WStatus = ERROR_INVALID_PARAMETER;
  5883. CLEANUP_CB(LocalBurContext->ErrorCallBack, L"HKey, KeyPathSizeInBytes, KeyPath",
  5884. WStatus, CLEANUP);
  5885. }
  5886. }
  5887. //
  5888. // Restart service or return the key
  5889. //
  5890. if (LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) {
  5891. if (LocalBurContext->BurFlags & (NTFRSAPI_BUR_FLAGS_SYSTEM |
  5892. NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY)) {
  5893. if (BurFlags & NTFRSAPI_BUR_FLAGS_RESTART) {
  5894. //
  5895. // Restart service; no key to move over
  5896. //
  5897. WStatus = NtFrsApiStartServiceAfterRestore(LocalBurContext->ErrorCallBack);
  5898. if (!WIN_SUCCESS(WStatus)) {
  5899. goto CLEANUP;
  5900. }
  5901. } else {
  5902. //
  5903. // Key hierarchy to move into final registry
  5904. //
  5905. *HKey = HKEY_LOCAL_MACHINE;
  5906. *KeyPathSizeInBytes = sizeof(WCHAR) *
  5907. (wcslen(FRS_BACKUP_RESTORE_MV_SECTION) + 1);
  5908. CopyMemory(KeyPath, FRS_BACKUP_RESTORE_MV_SECTION, *KeyPathSizeInBytes);
  5909. }
  5910. }
  5911. }
  5912. //
  5913. // SUCCESS
  5914. //
  5915. WStatus = ERROR_SUCCESS;
  5916. if (HANDLE_IS_VALID(LocalBurContext->BurSemaphore)) {
  5917. if (LocalBurContext->HaveBurSemaphore) {
  5918. ReleaseSemaphore(LocalBurContext->BurSemaphore, 1, NULL);
  5919. }
  5920. CloseHandle(LocalBurContext->BurSemaphore);
  5921. }
  5922. NtFrsApiFreeBurSets(&LocalBurContext->BurSets);
  5923. LocalBurContext->BurFiltersSizeInBytes = 0;
  5924. FREE(LocalBurContext->BurFilters);
  5925. FREE(LocalBurContext);
  5926. *BurContext = LocalBurContext;
  5927. CLEANUP:;
  5928. } except (EXCEPTION_EXECUTE_HANDLER) {
  5929. GET_EXCEPTION_CODE(WStatus);
  5930. }
  5931. //
  5932. // Clean up any handles, events, memory, ...
  5933. //
  5934. try {
  5935. } except (EXCEPTION_EXECUTE_HANDLER) {
  5936. GET_EXCEPTION_CODE(WStatus);
  5937. }
  5938. return WStatus;
  5939. }
  5940. DWORD
  5941. WINAPI
  5942. NtFrsApiGetBurSets(
  5943. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  5944. OUT PNTFRSAPI_BUR_SET *OutBurSets
  5945. )
  5946. /*++
  5947. Routine Description:
  5948. Retrieve the replica sets from the registry. Ignore tombstoned
  5949. sets.
  5950. Arguments:
  5951. ErrorCallBack - Ignored if NULL. Otherwise, call on error.
  5952. OutBurSets - Linked list of BurSets
  5953. Return Value:
  5954. Win32 Status
  5955. --*/
  5956. {
  5957. #undef NTFRSAPI_MODULE
  5958. #define NTFRSAPI_MODULE "NtFrsApiGetBurSets:"
  5959. DWORD WStatus;
  5960. DWORD KeyIdx;
  5961. DWORD RegType;
  5962. DWORD RegBytes;
  5963. DWORD ReplicaSetTombstoned;
  5964. PWCHAR SetPath = NULL;
  5965. PWCHAR ObjectName = NULL;
  5966. HKEY HSetsKey = 0;
  5967. HKEY HSetKey = 0;
  5968. PNTFRSAPI_BUR_SET LocalBurSet = NULL;
  5969. WCHAR RegBuf[MAX_PATH + 1];
  5970. *OutBurSets = NULL;
  5971. //
  5972. // Open the ntfrs parameters\replica sets section in the registry
  5973. //
  5974. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  5975. ErrorCallBack,
  5976. FRS_SETS_SECTION,
  5977. KEY_ENUMERATE_SUB_KEYS,
  5978. &HSetsKey);
  5979. if (!WIN_SUCCESS(WStatus)) {
  5980. goto CLEANUP;
  5981. }
  5982. //
  5983. // Enumerate the Replica Sets
  5984. //
  5985. KeyIdx = 0;
  5986. do {
  5987. WStatus = RegEnumKey(HSetsKey, KeyIdx, RegBuf, MAX_PATH + 1);
  5988. if (WStatus == ERROR_NO_MORE_ITEMS) {
  5989. break;
  5990. }
  5991. CLEANUP_CB(ErrorCallBack, FRS_SETS_SECTION, WStatus, CLEANUP);
  5992. //
  5993. // LocalBurSet->BurSetGuid (name of registry key)
  5994. //
  5995. LocalBurSet = NtFrsApi_Alloc(sizeof(NTFRSAPI_BUR_SET));
  5996. LocalBurSet->BurSetGuid = NtFrsApi_Dup(RegBuf);
  5997. SetPath = NtFrsApi_Cats(FRS_SETS_SECTION, L"\\", RegBuf);
  5998. //
  5999. // Open registry key for the Replica Set
  6000. //
  6001. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  6002. ErrorCallBack,
  6003. SetPath,
  6004. KEY_READ,
  6005. &HSetKey);
  6006. if (!WIN_SUCCESS(WStatus)) {
  6007. goto CLEANUP_DURING_LOOP;
  6008. }
  6009. //
  6010. // ReplicaSetTombstoned
  6011. // Ignore tombstoned replica sets
  6012. //
  6013. RegBytes = sizeof(DWORD);
  6014. WStatus = RegQueryValueEx(HSetKey,
  6015. REPLICA_SET_TOMBSTONED,
  6016. NULL,
  6017. &RegType,
  6018. (PUCHAR)&ReplicaSetTombstoned,
  6019. &RegBytes);
  6020. if (WIN_SUCCESS(WStatus) && RegType != REG_DWORD) {
  6021. ReplicaSetTombstoned = 0;
  6022. }
  6023. if (WIN_SUCCESS(WStatus) && ReplicaSetTombstoned) {
  6024. goto CLEANUP_DURING_LOOP;
  6025. }
  6026. //
  6027. // LocalBurSet->BurSetType
  6028. //
  6029. RegBytes = sizeof(RegBuf);
  6030. WStatus = RegQueryValueEx(HSetKey,
  6031. REPLICA_SET_TYPE,
  6032. NULL,
  6033. &RegType,
  6034. (PUCHAR)&RegBuf,
  6035. &RegBytes);
  6036. if (WIN_SUCCESS(WStatus) && RegType != REG_SZ) {
  6037. WStatus = ERROR_INVALID_PARAMETER;
  6038. }
  6039. if (!WIN_SUCCESS(WStatus)) {
  6040. ObjectName = NtFrsApi_Cats(SetPath, L"->", REPLICA_SET_TYPE);
  6041. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  6042. FREE(ObjectName);
  6043. goto CLEANUP_DURING_LOOP;
  6044. }
  6045. LocalBurSet->BurSetType = NtFrsApi_Dup(RegBuf);
  6046. //
  6047. // LocalBurSet->BurSetRoot
  6048. //
  6049. RegBytes = MAX_PATH + 1;
  6050. WStatus = RegQueryValueEx(HSetKey,
  6051. REPLICA_SET_ROOT,
  6052. NULL,
  6053. &RegType,
  6054. (PUCHAR)&RegBuf,
  6055. &RegBytes);
  6056. if (WIN_SUCCESS(WStatus) && RegType != REG_SZ) {
  6057. WStatus = ERROR_INVALID_PARAMETER;
  6058. }
  6059. if (!WIN_SUCCESS(WStatus)) {
  6060. ObjectName = NtFrsApi_Cats(SetPath, L"->", REPLICA_SET_ROOT);
  6061. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  6062. FREE(ObjectName);
  6063. goto CLEANUP_DURING_LOOP;
  6064. }
  6065. LocalBurSet->BurSetRoot = NtFrsApi_Dup(RegBuf);
  6066. //
  6067. // LocalBurSet->BurSetStage
  6068. //
  6069. RegBytes = MAX_PATH + 1;
  6070. WStatus = RegQueryValueEx(HSetKey,
  6071. REPLICA_SET_STAGE,
  6072. NULL,
  6073. &RegType,
  6074. (PUCHAR)&RegBuf,
  6075. &RegBytes);
  6076. if (WIN_SUCCESS(WStatus) && RegType != REG_SZ) {
  6077. WStatus = ERROR_INVALID_PARAMETER;
  6078. }
  6079. if (!WIN_SUCCESS(WStatus)) {
  6080. ObjectName = NtFrsApi_Cats(SetPath, L"->", REPLICA_SET_STAGE);
  6081. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  6082. FREE(ObjectName);
  6083. goto CLEANUP_DURING_LOOP;
  6084. }
  6085. LocalBurSet->BurSetStage = NtFrsApi_Dup(RegBuf);
  6086. //
  6087. // Link to list of BurSets
  6088. //
  6089. LocalBurSet->BurSetNext = *OutBurSets;
  6090. *OutBurSets = LocalBurSet;
  6091. LocalBurSet = NULL;
  6092. CLEANUP_DURING_LOOP:
  6093. RegCloseKey(HSetKey);
  6094. HSetKey = 0;
  6095. FREE(SetPath);
  6096. ++KeyIdx;
  6097. } while (TRUE);
  6098. //
  6099. // SUCCESS
  6100. //
  6101. WStatus = ERROR_SUCCESS;
  6102. CLEANUP:;
  6103. //
  6104. // Clean up any handles, events, memory, ...
  6105. //
  6106. if (HANDLE_IS_VALID(HSetsKey)) {
  6107. RegCloseKey(HSetsKey);
  6108. }
  6109. if (HANDLE_IS_VALID(HSetKey)) {
  6110. RegCloseKey(HSetKey);
  6111. }
  6112. if (LocalBurSet) {
  6113. FREE(LocalBurSet->BurSetGuid);
  6114. FREE(LocalBurSet->BurSetRoot);
  6115. FREE(LocalBurSet->BurSetStage);
  6116. FREE(LocalBurSet->BurSetType);
  6117. FREE(LocalBurSet);
  6118. }
  6119. FREE(SetPath);
  6120. FREE(ObjectName);
  6121. return WStatus;
  6122. }
  6123. DWORD
  6124. WINAPI
  6125. NtFrsApiGetBurFilters(
  6126. IN DWORD ErrorCallBack(IN PWCHAR, IN ULONG), OPTIONAL
  6127. OUT DWORD *OutBurFiltersSizeInBytes,
  6128. OUT PWCHAR *OutBurFilters
  6129. )
  6130. /*++
  6131. Routine Description:
  6132. Retrieve the ntfrs filter from FilesNotToBackup
  6133. Arguments:
  6134. ErrorCallBack - Ignored if NULL. Otherwise, call on error.
  6135. OutBurFiltersSizeInBytes - Size of *OutBurFiltes in bytes
  6136. OutBurFilters - Multistring filters
  6137. Return Value:
  6138. Win32 Status
  6139. --*/
  6140. {
  6141. #undef NTFRSAPI_MODULE
  6142. #define NTFRSAPI_MODULE "NtFrsApiGetBurFilters:"
  6143. DWORD WStatus;
  6144. DWORD RegType;
  6145. PWCHAR ObjectName;
  6146. HKEY HFilesKey = 0;
  6147. DWORD RegBytes = 16;
  6148. PWCHAR RegBuf = NULL;
  6149. *OutBurFiltersSizeInBytes = 0;
  6150. *OutBurFilters = NULL;
  6151. //
  6152. // Open the ntfrs parameters\replica sets section in the registry
  6153. //
  6154. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  6155. ErrorCallBack,
  6156. FRS_NEW_FILES_NOT_TO_BACKUP,
  6157. KEY_READ,
  6158. &HFilesKey);
  6159. if (!WIN_SUCCESS(WStatus)) {
  6160. WStatus = NtFrsApiOpenKeyEx(NTFRSAPI_MODULE,
  6161. ErrorCallBack,
  6162. FRS_OLD_FILES_NOT_TO_BACKUP,
  6163. KEY_QUERY_VALUE,
  6164. &HFilesKey);
  6165. }
  6166. if (!WIN_SUCCESS(WStatus)) {
  6167. goto CLEANUP;
  6168. }
  6169. //
  6170. // NtFrs Filters from FilesNotToBackup
  6171. //
  6172. RegBuf = NtFrsApi_Alloc(RegBytes);
  6173. WStatus = RegQueryValueEx(HFilesKey,
  6174. SERVICE_NAME,
  6175. NULL,
  6176. &RegType,
  6177. (PUCHAR)RegBuf,
  6178. &RegBytes);
  6179. if (WStatus == ERROR_MORE_DATA) {
  6180. FREE(RegBuf);
  6181. RegBuf = NtFrsApi_Alloc(RegBytes);
  6182. WStatus = RegQueryValueEx(HFilesKey,
  6183. SERVICE_NAME,
  6184. NULL,
  6185. &RegType,
  6186. (PUCHAR)RegBuf,
  6187. &RegBytes);
  6188. }
  6189. if (WIN_SUCCESS(WStatus) && RegType != REG_MULTI_SZ) {
  6190. WStatus = ERROR_INVALID_PARAMETER;
  6191. }
  6192. if (!WIN_SUCCESS(WStatus)) {
  6193. ObjectName = NtFrsApi_Cats(FRS_NEW_FILES_NOT_TO_BACKUP, L"->", SERVICE_NAME);
  6194. NtFrsApi_CallBackOnWStatus(ErrorCallBack, ObjectName, WStatus);
  6195. FREE(ObjectName);
  6196. goto CLEANUP;
  6197. }
  6198. //
  6199. // SUCCESS
  6200. //
  6201. *OutBurFiltersSizeInBytes = RegBytes;
  6202. *OutBurFilters = RegBuf;
  6203. RegBuf = NULL;
  6204. WStatus = ERROR_SUCCESS;
  6205. CLEANUP:;
  6206. //
  6207. // Clean up any handles, events, memory, ...
  6208. //
  6209. if (HANDLE_IS_VALID(HFilesKey)) {
  6210. RegCloseKey(HFilesKey);
  6211. }
  6212. if (RegBuf) {
  6213. FREE(RegBuf);
  6214. }
  6215. return WStatus;
  6216. }
  6217. DWORD
  6218. WINAPI
  6219. NtFrsApiGetBackupRestoreSets(
  6220. IN PVOID BurContext
  6221. )
  6222. /*++
  6223. Routine Description:
  6224. Cannot be called if BurContext is for a System restore.
  6225. Retrieves information about the current replicated directories
  6226. (AKA replica sets).
  6227. Arguments:
  6228. BurContext - From NtFrsApiInitializeBackupRestore()
  6229. Return Value:
  6230. Win32 Status
  6231. --*/
  6232. {
  6233. #undef NTFRSAPI_MODULE
  6234. #define NTFRSAPI_MODULE "NtFrsApiGetBackupRestoreSets:"
  6235. DWORD WStatus;
  6236. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  6237. try {
  6238. //
  6239. // VERIFY THE PARAMETERS
  6240. //
  6241. //
  6242. // Context
  6243. //
  6244. if (!LocalBurContext) {
  6245. WStatus = ERROR_INVALID_PARAMETER;
  6246. goto CLEANUP;
  6247. }
  6248. if (LocalBurContext->BurFlags & NTFRSAPI_BUR_FLAGS_SYSTEM) {
  6249. WStatus = ERROR_INVALID_PARAMETER;
  6250. goto CLEANUP;
  6251. }
  6252. //
  6253. // Free the current filters, if any
  6254. //
  6255. LocalBurContext->BurFiltersSizeInBytes = 0;
  6256. FREE(LocalBurContext->BurFilters);
  6257. //
  6258. // Free current BurSets, if any
  6259. //
  6260. NtFrsApiFreeBurSets(&LocalBurContext->BurSets);
  6261. //
  6262. // Fetch the backup restore sets
  6263. //
  6264. WStatus = NtFrsApiGetBurSets(LocalBurContext->ErrorCallBack,
  6265. &LocalBurContext->BurSets);
  6266. if (!WIN_SUCCESS(WStatus)) {
  6267. goto CLEANUP;
  6268. }
  6269. //
  6270. // Fetch the backup restore filters
  6271. //
  6272. WStatus = NtFrsApiGetBurFilters(LocalBurContext->ErrorCallBack,
  6273. &LocalBurContext->BurFiltersSizeInBytes,
  6274. &LocalBurContext->BurFilters);
  6275. if (!WIN_SUCCESS(WStatus)) {
  6276. // Ignore errors
  6277. WStatus = ERROR_SUCCESS;
  6278. }
  6279. //
  6280. // SUCCESS
  6281. //
  6282. WStatus = ERROR_SUCCESS;
  6283. CLEANUP:;
  6284. } except (EXCEPTION_EXECUTE_HANDLER) {
  6285. GET_EXCEPTION_CODE(WStatus);
  6286. }
  6287. //
  6288. // Clean up any handles, events, memory, ...
  6289. //
  6290. try {
  6291. } except (EXCEPTION_EXECUTE_HANDLER) {
  6292. GET_EXCEPTION_CODE(WStatus);
  6293. }
  6294. return WStatus;
  6295. }
  6296. DWORD
  6297. WINAPI
  6298. NtFrsApiEnumBackupRestoreSets(
  6299. IN PVOID BurContext,
  6300. IN DWORD BurSetIndex,
  6301. OUT PVOID *BurSet
  6302. )
  6303. /*++
  6304. Routine Description:
  6305. Returns ERROR_NO_MORE_ITEMS if BurSetIndex exceeds the number of
  6306. sets returned by NtFrsApiGetBackupRestoreSets().
  6307. Arguments:
  6308. BurContext - From NtFrsApiInitializeBackupRestore()
  6309. BurSetIndex - Index of set. Starts at 0.
  6310. BurSet - Opaque struct representing a replicating directory.
  6311. Return Value:
  6312. Win32 Status
  6313. --*/
  6314. {
  6315. #undef NTFRSAPI_MODULE
  6316. #define NTFRSAPI_MODULE "NtFrsApiEnumBackupRestoreSets:"
  6317. DWORD WStatus;
  6318. PNTFRSAPI_BUR_SET LocalBurSet;
  6319. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  6320. try {
  6321. //
  6322. // VERIFY THE PARAMETERS
  6323. //
  6324. //
  6325. // Context
  6326. //
  6327. if (!LocalBurContext) {
  6328. WStatus = ERROR_INVALID_PARAMETER;
  6329. goto CLEANUP;
  6330. }
  6331. if (!BurSet) {
  6332. WStatus = ERROR_INVALID_PARAMETER;
  6333. goto CLEANUP;
  6334. }
  6335. *BurSet = NULL;
  6336. //
  6337. // Find the correct set
  6338. //
  6339. for (LocalBurSet = LocalBurContext->BurSets;
  6340. LocalBurSet && BurSetIndex;
  6341. LocalBurSet = LocalBurSet->BurSetNext, --BurSetIndex) {
  6342. }
  6343. if (!LocalBurSet) {
  6344. WStatus = ERROR_NO_MORE_ITEMS;
  6345. goto CLEANUP;
  6346. }
  6347. //
  6348. // SUCCESS
  6349. //
  6350. WStatus = ERROR_SUCCESS;
  6351. *BurSet = LocalBurSet;
  6352. CLEANUP:;
  6353. } except (EXCEPTION_EXECUTE_HANDLER) {
  6354. //
  6355. // Exception (may be RPC)
  6356. //
  6357. GET_EXCEPTION_CODE(WStatus);
  6358. }
  6359. //
  6360. // Clean up any handles, events, memory, ...
  6361. //
  6362. try {
  6363. //
  6364. // Cleanup handles, memory, ...
  6365. //
  6366. } except (EXCEPTION_EXECUTE_HANDLER) {
  6367. GET_EXCEPTION_CODE(WStatus);
  6368. }
  6369. return WStatus;
  6370. }
  6371. DWORD
  6372. WINAPI
  6373. NtFrsApiIsBackupRestoreSetASysvol(
  6374. IN PVOID BurContext,
  6375. IN PVOID BurSet,
  6376. OUT BOOL *IsSysvol
  6377. )
  6378. /*++
  6379. Routine Description:
  6380. Does the specified BurSet represent a replicating SYSVOL share?
  6381. Arguments:
  6382. BurContext - From NtFrsApiInitializeBackupRestore()
  6383. BurSet - Opaque struct representing a replicating directory.
  6384. Returned by NtFrsApiEnumBackupRestoreSets(). Not
  6385. valid across calls to NtFrsApiGetBackupRestoreSets().
  6386. IsSysvol - TRUE : set is a system volume (AKA SYSVOL).
  6387. FALSE: set is a not a system volume (AKA SYSVOL).
  6388. Return Value:
  6389. Win32 Status
  6390. --*/
  6391. {
  6392. #undef NTFRSAPI_MODULE
  6393. #define NTFRSAPI_MODULE "NtFrsApiBackupRestoreSetIsSysvol:"
  6394. DWORD WStatus;
  6395. PNTFRSAPI_BUR_SET LocalBurSet;
  6396. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  6397. try {
  6398. //
  6399. // VERIFY THE PARAMETERS
  6400. //
  6401. //
  6402. // Context
  6403. //
  6404. if (!LocalBurContext) {
  6405. WStatus = ERROR_INVALID_PARAMETER;
  6406. goto CLEANUP;
  6407. }
  6408. if (!BurSet) {
  6409. WStatus = ERROR_INVALID_PARAMETER;
  6410. goto CLEANUP;
  6411. }
  6412. if (!IsSysvol) {
  6413. WStatus = ERROR_INVALID_PARAMETER;
  6414. goto CLEANUP;
  6415. }
  6416. //
  6417. // Locate BurSet
  6418. //
  6419. for (LocalBurSet = LocalBurContext->BurSets;
  6420. LocalBurSet && (LocalBurSet != BurSet);
  6421. LocalBurSet = LocalBurSet->BurSetNext) {
  6422. }
  6423. if (!LocalBurSet) {
  6424. WStatus = ERROR_NOT_FOUND;
  6425. goto CLEANUP;
  6426. }
  6427. //
  6428. // If a type were specified and it is Enterprise or Domain
  6429. //
  6430. if (LocalBurSet->BurSetType &&
  6431. (WSTR_EQ(LocalBurSet->BurSetType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) ||
  6432. WSTR_EQ(LocalBurSet->BurSetType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN))) {
  6433. *IsSysvol = TRUE;
  6434. } else {
  6435. *IsSysvol = FALSE;
  6436. }
  6437. //
  6438. // SUCCESS
  6439. //
  6440. WStatus = ERROR_SUCCESS;
  6441. CLEANUP:;
  6442. } except (EXCEPTION_EXECUTE_HANDLER) {
  6443. //
  6444. // Exception (may be RPC)
  6445. //
  6446. GET_EXCEPTION_CODE(WStatus);
  6447. }
  6448. //
  6449. // Clean up any handles, events, memory, ...
  6450. //
  6451. try {
  6452. //
  6453. // Cleanup handles, memory, ...
  6454. //
  6455. } except (EXCEPTION_EXECUTE_HANDLER) {
  6456. GET_EXCEPTION_CODE(WStatus);
  6457. }
  6458. return WStatus;
  6459. }
  6460. DWORD
  6461. WINAPI
  6462. NtFrsApiGetBackupRestoreSetDirectory(
  6463. IN PVOID BurContext,
  6464. IN PVOID BurSet,
  6465. IN OUT DWORD *DirectoryPathSizeInBytes,
  6466. OUT PWCHAR DirectoryPath
  6467. )
  6468. /*++
  6469. Routine Description:
  6470. Return the path of the replicating directory represented by BurSet.
  6471. Arguments:
  6472. BurContext - From NtFrsApiInitializeBackupRestore()
  6473. BurSet - Opaque struct representing a replicating directory.
  6474. Returned by NtFrsApiEnumBackupRestoreSets(). Not
  6475. valid across calls to NtFrsApiGetBackupRestoreSets().
  6476. DirectoryPathSizeInBytes - Address of DWORD giving size of
  6477. DirectoryPath. Cannot be NULL.
  6478. Set to the number of bytes needed
  6479. to return DirectoryPath.
  6480. ERROR_INSUFFICIENT_BUFFER is returned if
  6481. DirectoryPath is too small.
  6482. DirectoryPath - Buffer that is *DirectoryPathSizeInBytes
  6483. bytes in length. Contains path of replicating
  6484. directory.
  6485. Return Value:
  6486. Win32 Status
  6487. --*/
  6488. {
  6489. #undef NTFRSAPI_MODULE
  6490. #define NTFRSAPI_MODULE "NtFrsApiGetBackupRestoreSetDirectory:"
  6491. DWORD WStatus;
  6492. DWORD DirectorySize;
  6493. PNTFRSAPI_BUR_SET LocalBurSet;
  6494. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  6495. try {
  6496. //
  6497. // VERIFY THE PARAMETERS
  6498. //
  6499. //
  6500. // Context
  6501. //
  6502. if (!LocalBurContext) {
  6503. WStatus = ERROR_INVALID_PARAMETER;
  6504. goto CLEANUP;
  6505. }
  6506. if (!BurSet) {
  6507. WStatus = ERROR_INVALID_PARAMETER;
  6508. goto CLEANUP;
  6509. }
  6510. if (!DirectoryPathSizeInBytes) {
  6511. WStatus = ERROR_INVALID_PARAMETER;
  6512. goto CLEANUP;
  6513. }
  6514. if (*DirectoryPathSizeInBytes && !DirectoryPath) {
  6515. WStatus = ERROR_INVALID_PARAMETER;
  6516. goto CLEANUP;
  6517. }
  6518. //
  6519. // Re-locate BurSet
  6520. //
  6521. for (LocalBurSet = LocalBurContext->BurSets;
  6522. LocalBurSet && (LocalBurSet != BurSet);
  6523. LocalBurSet = LocalBurSet->BurSetNext) {
  6524. }
  6525. if (!LocalBurSet) {
  6526. WStatus = ERROR_NOT_FOUND;
  6527. goto CLEANUP;
  6528. }
  6529. DirectorySize = (wcslen(LocalBurSet->BurSetRoot) + 1) * sizeof(WCHAR);
  6530. if (DirectorySize > *DirectoryPathSizeInBytes) {
  6531. WStatus = ERROR_INSUFFICIENT_BUFFER;
  6532. *DirectoryPathSizeInBytes = DirectorySize;
  6533. goto CLEANUP;
  6534. }
  6535. *DirectoryPathSizeInBytes = DirectorySize;
  6536. CopyMemory(DirectoryPath, LocalBurSet->BurSetRoot, DirectorySize);
  6537. //
  6538. // SUCCESS
  6539. //
  6540. WStatus = ERROR_SUCCESS;
  6541. CLEANUP:;
  6542. } except (EXCEPTION_EXECUTE_HANDLER) {
  6543. GET_EXCEPTION_CODE(WStatus);
  6544. }
  6545. //
  6546. // Clean up any handles, events, memory, ...
  6547. //
  6548. try {
  6549. } except (EXCEPTION_EXECUTE_HANDLER) {
  6550. GET_EXCEPTION_CODE(WStatus);
  6551. }
  6552. return WStatus;
  6553. }
  6554. DWORD
  6555. WINAPI
  6556. NtFrsApiGetBackupRestoreSetPaths(
  6557. IN PVOID BurContext,
  6558. IN PVOID BurSet,
  6559. IN OUT DWORD *PathsSizeInBytes,
  6560. OUT PWCHAR Paths,
  6561. IN OUT DWORD *FiltersSizeInBytes,
  6562. OUT PWCHAR Filters
  6563. )
  6564. /*++
  6565. Routine Description:
  6566. Return a multistring that contains the paths to other files
  6567. and directories needed for proper operation of the replicated
  6568. directory represented by BurSet. Return another multistring
  6569. that details the backup filters to be applied to the paths
  6570. returned by this function and the path returned by
  6571. NtFrsApiGetBackupRestoreSetDirectory().
  6572. The paths may overlap the replicated directory.
  6573. The paths may contain nested entries.
  6574. Filters is a multistring in the same format as the values for
  6575. the registry key FilesNotToBackup.
  6576. The replicated directory can be found with
  6577. NtFrsApiGetBackupRestoreSetDirectory(). The replicated directory
  6578. may overlap one or more entries in Paths.
  6579. ERROR_PATH_NOT_FOUND is returned if the paths could not be
  6580. determined.
  6581. Arguments:
  6582. BurContext - From NtFrsApiInitializeBackupRestore()
  6583. BurSet - Opaque struct representing a replicating directory.
  6584. Returned by NtFrsApiEnumBackupRestoreSets(). Not
  6585. valid across calls to NtFrsApiGetBackupRestoreSets().
  6586. PathsSizeInBytes - Address of DWORD giving size of Paths.
  6587. Cannot be NULL. Set to the number of bytes
  6588. needed to return Paths.
  6589. ERROR_INSUFFICIENT_BUFFER is returned if
  6590. Paths is too small.
  6591. Paths - Buffer that is *PathsSizeInBytes
  6592. bytes in length. Contains the paths of the
  6593. other files and directories needed for proper
  6594. operation of the replicated directory.
  6595. FiltersSizeInBytes - Address of DWORD giving size of Filters.
  6596. Cannot be NULL. Set to the number of bytes
  6597. needed to return Filters.
  6598. ERROR_INSUFFICIENT_BUFFER is returned if
  6599. Filters is too small.
  6600. Filters - Buffer that is *FiltersSizeInBytes bytes in
  6601. length. Contains the backup filters to be
  6602. applied to Paths, the contents of directories
  6603. in Paths, and the replicated directory.
  6604. Return Value:
  6605. Win32 Status
  6606. --*/
  6607. {
  6608. #undef NTFRSAPI_MODULE
  6609. #define NTFRSAPI_MODULE "NtFrsApiGetBackupRestoreSetPaths:"
  6610. DWORD WStatus;
  6611. DWORD PathsSize;
  6612. LONG NChars;
  6613. PWCHAR Path;
  6614. PNTFRSAPI_BUR_SET LocalBurSet;
  6615. PNTFRSAPI_BUR_CONTEXT LocalBurContext = BurContext;
  6616. try {
  6617. //
  6618. // VERIFY THE PARAMETERS
  6619. //
  6620. //
  6621. // Context
  6622. //
  6623. if (!LocalBurContext) {
  6624. WStatus = ERROR_INVALID_PARAMETER;
  6625. goto CLEANUP;
  6626. }
  6627. if (!BurSet) {
  6628. WStatus = ERROR_INVALID_PARAMETER;
  6629. goto CLEANUP;
  6630. }
  6631. if (!PathsSizeInBytes) {
  6632. WStatus = ERROR_INVALID_PARAMETER;
  6633. goto CLEANUP;
  6634. }
  6635. if (*PathsSizeInBytes && !Paths) {
  6636. WStatus = ERROR_INVALID_PARAMETER;
  6637. goto CLEANUP;
  6638. }
  6639. //
  6640. // Re-locate BurSet
  6641. //
  6642. for (LocalBurSet = LocalBurContext->BurSets;
  6643. LocalBurSet && (LocalBurSet != BurSet);
  6644. LocalBurSet = LocalBurSet->BurSetNext) {
  6645. }
  6646. if (!LocalBurSet) {
  6647. WStatus = ERROR_NOT_FOUND;
  6648. goto CLEANUP;
  6649. }
  6650. //
  6651. // Sysvol; return sysvol root
  6652. //
  6653. if (LocalBurSet->BurSetType &&
  6654. (WSTR_EQ(LocalBurSet->BurSetType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) ||
  6655. WSTR_EQ(LocalBurSet->BurSetType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN))) {
  6656. Path = LocalBurSet->BurSetRoot;
  6657. //
  6658. // Skip trailing \'s
  6659. //
  6660. NChars = wcslen(Path) - 1;
  6661. while (NChars >= 0) {
  6662. if (Path[NChars] != L'\\') {
  6663. break;
  6664. }
  6665. --NChars;
  6666. }
  6667. //
  6668. // Find the last \ that isn't a trailing \
  6669. //
  6670. while (NChars >= 0) {
  6671. if (Path[NChars] == L'\\') {
  6672. break;
  6673. }
  6674. --NChars;
  6675. }
  6676. //
  6677. // Skip dup \'s
  6678. //
  6679. while (NChars >= 0) {
  6680. if (Path[NChars] != L'\\') {
  6681. break;
  6682. }
  6683. --NChars;
  6684. }
  6685. //
  6686. // Convert index into number of chars
  6687. //
  6688. ++NChars;
  6689. //
  6690. // Sysvol path must contain at least 3 chars; <driver letter>:\
  6691. //
  6692. if (NChars < 4) {
  6693. WStatus = ERROR_NOT_FOUND;
  6694. goto CLEANUP;
  6695. }
  6696. } else {
  6697. //
  6698. // Not a Sysvol; return staging path
  6699. //
  6700. Path = LocalBurSet->BurSetStage;
  6701. NChars = wcslen(Path);
  6702. }
  6703. //
  6704. // Is the Paths and Filters buffers big enough?
  6705. //
  6706. PathsSize = (NChars + 1 + 1) * sizeof(WCHAR);
  6707. if (PathsSize > *PathsSizeInBytes ||
  6708. LocalBurContext->BurFiltersSizeInBytes > *FiltersSizeInBytes) {
  6709. *PathsSizeInBytes = PathsSize;
  6710. *FiltersSizeInBytes = LocalBurContext->BurFiltersSizeInBytes;
  6711. WStatus = ERROR_INSUFFICIENT_BUFFER;
  6712. goto CLEANUP;
  6713. }
  6714. //
  6715. // Yep; buffers are big enough
  6716. //
  6717. *PathsSizeInBytes = PathsSize;
  6718. *FiltersSizeInBytes = LocalBurContext->BurFiltersSizeInBytes;
  6719. //
  6720. // Copy the sysvol or staging path
  6721. //
  6722. CopyMemory(Paths, Path, NChars * sizeof(WCHAR));
  6723. Paths[NChars + 0] = L'\0';
  6724. Paths[NChars + 1] = L'\0';
  6725. //
  6726. // Filters
  6727. //
  6728. if (LocalBurContext->BurFiltersSizeInBytes) {
  6729. CopyMemory(Filters, LocalBurContext->BurFilters, LocalBurContext->BurFiltersSizeInBytes);
  6730. }
  6731. //
  6732. // SUCCESS
  6733. //
  6734. WStatus = ERROR_SUCCESS;
  6735. CLEANUP:;
  6736. } except (EXCEPTION_EXECUTE_HANDLER) {
  6737. GET_EXCEPTION_CODE(WStatus);
  6738. }
  6739. //
  6740. // Clean up any handles, events, memory, ...
  6741. //
  6742. try {
  6743. } except (EXCEPTION_EXECUTE_HANDLER) {
  6744. GET_EXCEPTION_CODE(WStatus);
  6745. }
  6746. return WStatus;
  6747. }
  6748. DWORD
  6749. WINAPI
  6750. NtFrsApi_DeleteSysvolMember(
  6751. IN PSEC_WINNT_AUTH_IDENTITY_W pCreds,
  6752. IN PWCHAR BindingDC,
  6753. IN PWCHAR NTDSSettingsDn,
  6754. IN OPTIONAL PWCHAR ComputerDn
  6755. )
  6756. /*++
  6757. Routine Description:
  6758. This API is written to be called from NTDSUTIL.EXE to remove
  6759. FRS member and subscriber object for a server that is being
  6760. removed (without dcpromo-demote) from the list of DCs.
  6761. Arguments:
  6762. pCreds p Credentials used to bind to the DS.
  6763. BindingDC - Name of a DC to perform the delete on.
  6764. NTDSSettingsDn - Dn of the "NTDS Settings" object for the server
  6765. that is being removed from the sysvol replica set.
  6766. ComputerDn - Dn of the computer object for the server that is
  6767. being removed from the sysvol replica set.
  6768. Return Value:
  6769. Win32 Status
  6770. --*/
  6771. {
  6772. #undef NTFRSAPI_MODULE
  6773. #define NTFRSAPI_MODULE "NtFrsApi_DeleteSysvolMember:"
  6774. PLDAP pLdap = NULL;
  6775. DWORD LStatus = LDAP_SUCCESS;
  6776. DWORD WStatus = ERROR_SUCCESS;
  6777. PWCHAR DefaultNcDn = NULL;
  6778. PWCHAR SystemDn = NULL;
  6779. PWCHAR NtfrsSettingsDn = NULL;
  6780. PWCHAR ReplicaSetDn = NULL;
  6781. PWCHAR MemberDn = NULL;
  6782. PWCHAR ComputerRef = NULL;
  6783. PWCHAR SubscriberDn = NULL;
  6784. PLDAPMessage LdapEntry;
  6785. PLDAPMessage LdapMsg = NULL;
  6786. PWCHAR *Values = NULL;
  6787. PWCHAR Attrs[2];
  6788. PWCHAR SearchFilter = NULL;
  6789. DWORD NoOfMembers;
  6790. DWORD NoOfSubscribers;
  6791. PWCHAR MemberAttrs[4];
  6792. PWCHAR SubscriberAttrs[3];
  6793. FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
  6794. if ((BindingDC == NULL) || (NTDSSettingsDn == NULL)) {
  6795. return ERROR_INVALID_PARAMETER;
  6796. }
  6797. WStatus = FrsSupBindToDC (BindingDC, pCreds, &pLdap);
  6798. if (WStatus != ERROR_SUCCESS) {
  6799. goto CLEANUP;
  6800. }
  6801. //
  6802. // Find the naming contexts and the default naming context (objectCategory=*)
  6803. //
  6804. MK_ATTRS_1(Attrs, ATTR_DEFAULT_NAMING_CONTEXT);
  6805. if (!FrsSupLdapSearch(pLdap, CN_ROOT, LDAP_SCOPE_BASE, CATEGORY_ANY,
  6806. Attrs, 0, &LdapMsg)) {
  6807. goto CLEANUP;
  6808. }
  6809. LdapEntry = ldap_first_entry(pLdap, LdapMsg);
  6810. if (LdapEntry == NULL) {
  6811. goto CLEANUP;
  6812. }
  6813. //
  6814. // Find the default naming context
  6815. //
  6816. Values = (PWCHAR *)FrsSupFindValues(pLdap, LdapEntry, ATTR_DEFAULT_NAMING_CONTEXT, FALSE);
  6817. if (Values == NULL) {
  6818. WStatus = ERROR_NOT_FOUND;
  6819. goto CLEANUP;
  6820. }
  6821. DefaultNcDn = FrsSupWcsDup(Values[0]);
  6822. SystemDn = FrsSupExtendDn(DefaultNcDn, CN_SYSTEM);
  6823. NtfrsSettingsDn = FrsSupExtendDn(SystemDn, CN_NTFRS_SETTINGS);
  6824. ReplicaSetDn = FrsSupExtendDn(NtfrsSettingsDn, CN_DOMAIN_SYSVOL);
  6825. if (ReplicaSetDn == NULL) {
  6826. WStatus = ERROR_OUTOFMEMORY;
  6827. }
  6828. //
  6829. // Find member DN
  6830. //
  6831. if (ComputerDn != NULL) {
  6832. SearchFilter = (PWCHAR)malloc(sizeof(WCHAR) * (1 + wcslen(ComputerDn) +
  6833. wcslen(NTDSSettingsDn) + MAX_PATH));
  6834. if (SearchFilter == NULL) {
  6835. WStatus = ERROR_OUTOFMEMORY;
  6836. goto CLEANUP;
  6837. }
  6838. //
  6839. // e.g. (&(objectClass=nTFRSmember)
  6840. // (|(frsComputerReference=<computerdn>)(serverReference=<ntdssettingsdn>)))
  6841. //
  6842. wcscpy(SearchFilter, L"(&");
  6843. wcscat(SearchFilter, CLASS_MEMBER);
  6844. wcscat(SearchFilter, L"(|(");
  6845. wcscat(SearchFilter, ATTR_COMPUTER_REF);
  6846. wcscat(SearchFilter, L"=");
  6847. wcscat(SearchFilter, ComputerDn);
  6848. wcscat(SearchFilter, L")(");
  6849. wcscat(SearchFilter, ATTR_SERVER_REF);
  6850. wcscat(SearchFilter, L"=");
  6851. wcscat(SearchFilter, NTDSSettingsDn);
  6852. wcscat(SearchFilter, L")))");
  6853. } else {
  6854. SearchFilter = (PWCHAR)malloc(sizeof(WCHAR) * (1 + wcslen(NTDSSettingsDn) + MAX_PATH));
  6855. if (SearchFilter == NULL) {
  6856. WStatus = ERROR_OUTOFMEMORY;
  6857. goto CLEANUP;
  6858. }
  6859. //
  6860. // e.g. (&(objectClass=nTFRSmember)(serverReference=<ntdssettingsdn>))
  6861. //
  6862. wcscpy(SearchFilter, L"(&");
  6863. wcscat(SearchFilter, CLASS_MEMBER);
  6864. wcscat(SearchFilter, L"(");
  6865. wcscat(SearchFilter, ATTR_SERVER_REF);
  6866. wcscat(SearchFilter, L"=");
  6867. wcscat(SearchFilter, NTDSSettingsDn);
  6868. wcscat(SearchFilter, L"))");
  6869. }
  6870. MK_ATTRS_3(MemberAttrs, ATTR_DN, ATTR_COMPUTER_REF, ATTR_SERVER_REF);
  6871. if (!FrsSupLdapSearchInit(pLdap,
  6872. ReplicaSetDn,
  6873. LDAP_SCOPE_SUBTREE,
  6874. SearchFilter,
  6875. MemberAttrs,
  6876. 0,
  6877. &FrsSearchContext)) {
  6878. WStatus = ERROR_NOT_FOUND;
  6879. goto CLEANUP;
  6880. }
  6881. NoOfMembers = FrsSearchContext.EntriesInPage;
  6882. if (NoOfMembers == 0) {
  6883. FrsSupLdapSearchClose(&FrsSearchContext);
  6884. WStatus = ERROR_NOT_FOUND;
  6885. goto CLEANUP;
  6886. }
  6887. if (NoOfMembers > 1) {
  6888. FrsSupLdapSearchClose(&FrsSearchContext);
  6889. WStatus = ERROR_NOT_FOUND;
  6890. goto CLEANUP;
  6891. }
  6892. //
  6893. // Scan the entries returned from ldap_search
  6894. //
  6895. for (LdapEntry = FrsSupLdapSearchNext(pLdap, &FrsSearchContext);
  6896. LdapEntry != NULL;
  6897. LdapEntry = FrsSupLdapSearchNext(pLdap, &FrsSearchContext)) {
  6898. MemberDn = FrsSupFindValue(pLdap, LdapEntry, ATTR_DN);
  6899. if (ComputerDn == NULL) {
  6900. ComputerRef = FrsSupFindValue(pLdap, LdapEntry, ATTR_COMPUTER_REF);
  6901. } else {
  6902. ComputerRef = FrsSupWcsDup(ComputerDn);
  6903. }
  6904. }
  6905. FrsSupLdapSearchClose(&FrsSearchContext);
  6906. //
  6907. // Find subscriber DN. Delete the member even if subscriber is not
  6908. // found.
  6909. //
  6910. FRS_SUP_FREE(SearchFilter);
  6911. if (ComputerRef == NULL) {
  6912. goto DODELETE;
  6913. }
  6914. SearchFilter = (PWCHAR)malloc(sizeof(WCHAR) * (1 + wcslen(MemberDn) + MAX_PATH));
  6915. if (SearchFilter == NULL) {
  6916. WStatus = ERROR_OUTOFMEMORY;
  6917. goto DODELETE;
  6918. }
  6919. wcscpy(SearchFilter, L"(&");
  6920. wcscat(SearchFilter, CLASS_SUBSCRIBER);
  6921. wcscat(SearchFilter, L"(");
  6922. wcscat(SearchFilter, ATTR_MEMBER_REF);
  6923. wcscat(SearchFilter, L"=");
  6924. wcscat(SearchFilter, MemberDn);
  6925. wcscat(SearchFilter, L"))");
  6926. MK_ATTRS_2(SubscriberAttrs, ATTR_DN, ATTR_MEMBER_REF);
  6927. if (!FrsSupLdapSearchInit(pLdap,
  6928. ComputerRef,
  6929. LDAP_SCOPE_SUBTREE,
  6930. SearchFilter,
  6931. SubscriberAttrs,
  6932. 0,
  6933. &FrsSearchContext)) {
  6934. WStatus = ERROR_NOT_FOUND;
  6935. goto DODELETE;
  6936. }
  6937. NoOfSubscribers = FrsSearchContext.EntriesInPage;
  6938. if (NoOfSubscribers != 1) {
  6939. FrsSupLdapSearchClose(&FrsSearchContext);
  6940. WStatus = ERROR_NOT_FOUND;
  6941. goto DODELETE;
  6942. }
  6943. //
  6944. // Scan the entries returned from ldap_search
  6945. //
  6946. for (LdapEntry = FrsSupLdapSearchNext(pLdap, &FrsSearchContext);
  6947. LdapEntry != NULL;
  6948. LdapEntry = FrsSupLdapSearchNext(pLdap, &FrsSearchContext)) {
  6949. SubscriberDn = FrsSupFindValue(pLdap, LdapEntry, ATTR_DN);
  6950. }
  6951. FrsSupLdapSearchClose(&FrsSearchContext);
  6952. DODELETE:
  6953. //
  6954. // Now we have both the member dn and the subscriber dn.
  6955. //
  6956. if (SubscriberDn != NULL) {
  6957. LStatus = ldap_delete_s(pLdap, SubscriberDn);
  6958. if (LStatus != LDAP_SUCCESS) {
  6959. WStatus = ERROR_INTERNAL_ERROR;
  6960. }
  6961. }
  6962. if (MemberDn != NULL) {
  6963. LStatus = ldap_delete_s(pLdap, MemberDn);
  6964. if (LStatus != LDAP_SUCCESS) {
  6965. WStatus = ERROR_INTERNAL_ERROR;
  6966. }
  6967. }
  6968. CLEANUP:
  6969. if (pLdap != NULL) {
  6970. ldap_unbind_s(pLdap);
  6971. }
  6972. LDAP_FREE_VALUES(Values);
  6973. LDAP_FREE_MSG(LdapMsg);
  6974. FRS_SUP_FREE(SearchFilter);
  6975. FRS_SUP_FREE(DefaultNcDn);
  6976. FRS_SUP_FREE(SystemDn);
  6977. FRS_SUP_FREE(NtfrsSettingsDn);
  6978. FRS_SUP_FREE(ReplicaSetDn);
  6979. FRS_SUP_FREE(MemberDn);
  6980. FRS_SUP_FREE(ComputerRef);
  6981. FRS_SUP_FREE(SubscriberDn);
  6982. return WStatus;
  6983. }