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

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