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.

969 lines
27 KiB

  1. extern "C" {
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <ntioapi.h>
  6. #include <windows.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <lm.h>
  10. #include <netcan.h>
  11. #include <icanon.h>
  12. #include <dsgetdc.h>
  13. #include <dsrole.h>
  14. }
  15. /*
  16. * This program performs the steps necessary to configure NTFRS on a DC, prepared
  17. * to support the system and enterprise volumes.
  18. *
  19. * It was created as an interim tool to support the initialization of NTFRS on a DC
  20. * which was running NT5 generation software before NTFRS was available. After upgrading
  21. * that DC with the latest NT5 version, this tool must be manually run to complete the
  22. * initialization of NTFRS and system volumes.
  23. */
  24. WCHAR SysVolShare[] = L"SYSVOL";
  25. WCHAR SysVolRemark[] = L"System Volume Share (Migrated)";
  26. WCHAR FRSSysvol[] = L"System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Sysvol";
  27. #define DSROLEP_FRS_COMMAND L"Replica Set Command"
  28. #define DSROLEP_FRS_NAME L"Replica Set Name"
  29. #define DSROLEP_FRS_TYPE L"Replica Set Type"
  30. #define DSROLEP_FRS_PRIMARY L"Replica Set Primary"
  31. #define DSROLEP_FRS_STAGE L"Replica Set Stage"
  32. #define DSROLEP_FRS_ROOT L"Replica Set Root"
  33. #define DSROLEP_FRS_CREATE L"Create"
  34. #define DSROLEP_FRS_DELETE L"Delete"
  35. #define DSROLEP_FRS_COMMITTED L"SysVol Information is Committed"
  36. #define DSROLEP_FRS_LONG_NAME L"Microsoft File Replication Service"
  37. #define DSROLEP_FRS_SHORT_NAME L"NtFrs"
  38. //
  39. // These are the static directories created within a system volume share
  40. //
  41. LPWSTR StaticSysvolDirs[] = {
  42. L"sysvol",
  43. L"domain",
  44. L"enterprise",
  45. L"staging",
  46. L"staging areas",
  47. L"sysvol\\enterprise",
  48. L"staging\\domain",
  49. L"staging\\enterprise",
  50. 0
  51. };
  52. //
  53. // Print out the usage message
  54. //
  55. void
  56. Usage( int argc, char *argv[] )
  57. {
  58. fprintf( stderr, "Usage: %s [-D] [-E] sysvol\n\n", argv[0] );
  59. fprintf( stderr, " -D this is the first upgraded DC in this domain\n\n" );
  60. fprintf( stderr, " -E this is the first upgraded DC in this enterprise\n\n" );
  61. fprintf( stderr, " sysvol is the path for the system volume share.\n" );
  62. fprintf( stderr, " The system volume must reside on NTFS version 5\n" );
  63. }
  64. //
  65. // Print 'text' and render 'code' into an error message
  66. //
  67. void
  68. errmsg( char *text, ULONG code )
  69. {
  70. int i;
  71. char msg[ 100 ];
  72. i = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ),
  73. NULL,
  74. code,
  75. 0,
  76. msg,
  77. sizeof(msg),
  78. NULL );
  79. if( i )
  80. fprintf( stderr, "%s: %s\n", text ? text : "", msg );
  81. else
  82. fprintf( stderr, "%s: error %d\n", text ? text : "", code );
  83. }
  84. //
  85. // Print unicode 'text' and render 'code' into an error message
  86. //
  87. void
  88. errmsg( LPWSTR text, ULONG code )
  89. {
  90. int i;
  91. WCHAR msg[ 100 ];
  92. i = FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ),
  93. NULL,
  94. code,
  95. 0,
  96. msg,
  97. sizeof(msg),
  98. NULL );
  99. if( i )
  100. fprintf( stderr, "%ws: %ws\n", text ? text : L"", msg );
  101. else
  102. fprintf( stderr, "%ws: error %d\n", text ? text : L"", code );
  103. }
  104. //
  105. // Write a string value to the registry
  106. //
  107. BOOLEAN
  108. WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, LPWSTR Value )
  109. {
  110. HKEY hKey;
  111. DWORD disposition;
  112. LONG retval;
  113. //
  114. // First ensure that 'keyname' exists in the registry
  115. //
  116. retval = RegCreateKeyEx(
  117. HKEY_LOCAL_MACHINE,
  118. KeyName,
  119. NULL,
  120. NULL,
  121. REG_OPTION_NON_VOLATILE,
  122. KEY_ALL_ACCESS,
  123. NULL,
  124. &hKey,
  125. &disposition
  126. );
  127. if( retval != ERROR_SUCCESS ) {
  128. errmsg( KeyName, retval );
  129. return FALSE;
  130. }
  131. if( ARGUMENT_PRESENT( ValueName ) ) {
  132. retval = RegSetValueEx(
  133. hKey,
  134. ValueName,
  135. 0,
  136. REG_SZ,
  137. (BYTE *)Value,
  138. (wcslen( Value ) + 1) * sizeof( WCHAR )
  139. );
  140. if( retval != ERROR_SUCCESS ) {
  141. errmsg( ValueName, retval );
  142. RegCloseKey( hKey );
  143. return FALSE;
  144. }
  145. }
  146. RegCloseKey( hKey );
  147. return TRUE;
  148. }
  149. //
  150. // Write a DWORD value to the registry
  151. //
  152. BOOLEAN
  153. WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, DWORD Value )
  154. {
  155. HKEY hKey;
  156. DWORD disposition;
  157. LONG retval;
  158. //
  159. // First ensure that 'keyname' exists in the registry
  160. //
  161. retval = RegCreateKeyEx(
  162. HKEY_LOCAL_MACHINE,
  163. KeyName,
  164. NULL,
  165. NULL,
  166. REG_OPTION_NON_VOLATILE,
  167. KEY_ALL_ACCESS,
  168. NULL,
  169. &hKey,
  170. &disposition
  171. );
  172. if( retval != ERROR_SUCCESS ) {
  173. errmsg( KeyName, retval );
  174. return FALSE;
  175. }
  176. if( ARGUMENT_PRESENT( ValueName ) ) {
  177. retval = RegSetValueEx(
  178. hKey,
  179. ValueName,
  180. 0,
  181. REG_DWORD,
  182. (BYTE *)&Value,
  183. sizeof( Value )
  184. );
  185. if( retval != ERROR_SUCCESS ) {
  186. errmsg( ValueName, retval );
  187. RegCloseKey( hKey );
  188. return FALSE;
  189. }
  190. }
  191. RegCloseKey( hKey );
  192. return TRUE;
  193. }
  194. //
  195. // Make sure that 'DirName' exists. Create it if it doesn't
  196. //
  197. BOOLEAN
  198. EnsureDirectoryExists( LPWSTR DirName )
  199. {
  200. DWORD retval;
  201. retval = GetFileAttributes( DirName );
  202. if( retval == 0xFFFFFFFF ) {
  203. printf( " Create directory: %ws\n", DirName );
  204. if( !CreateDirectory( DirName, NULL ) ) {
  205. retval = GetLastError();
  206. errmsg( DirName, GetLastError() );
  207. return FALSE;
  208. }
  209. } else if( !(retval & FILE_ATTRIBUTE_DIRECTORY) ) {
  210. fprintf( stderr, "Not a directory: %ws\n", DirName );
  211. return FALSE;
  212. }
  213. return TRUE;
  214. }
  215. BOOLEAN
  216. LinkAToB( LPWSTR DirA, LPWSTR DirB )
  217. {
  218. NTSTATUS Status;
  219. HANDLE Handle;
  220. UNICODE_STRING UnicodeNameB;
  221. UNICODE_STRING DosNameB;
  222. IO_STATUS_BLOCK IoStatusBlock;
  223. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  224. PCHAR ReparseBuffer;
  225. USHORT ReparseDataLength;
  226. if( !EnsureDirectoryExists( DirA ) ||
  227. !EnsureDirectoryExists( DirB ) ) {
  228. return FALSE;
  229. }
  230. Handle = CreateFile( DirA,
  231. GENERIC_WRITE,
  232. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  233. NULL,
  234. OPEN_EXISTING,
  235. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  236. NULL
  237. );
  238. if( Handle == INVALID_HANDLE_VALUE ) {
  239. fprintf( stderr, "Unable to open %ws", DirA );
  240. errmsg( (LPWSTR)NULL, GetLastError() );
  241. return FALSE;
  242. }
  243. //
  244. // Get the NT path name of the directory to which we want to link
  245. //
  246. if( !RtlDosPathNameToNtPathName_U(
  247. DirB,
  248. &UnicodeNameB,
  249. NULL,
  250. NULL
  251. )) {
  252. errmsg( DirB, GetLastError() );
  253. return FALSE;
  254. }
  255. RtlInitUnicodeString( &DosNameB, DirB);
  256. //
  257. // Set the reparse point with mount point or symbolic link tag and determine
  258. // the appropriate length of the buffer.
  259. //
  260. ReparseDataLength = (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
  261. REPARSE_DATA_BUFFER_HEADER_SIZE) +
  262. UnicodeNameB.Length + sizeof(UNICODE_NULL) +
  263. DosNameB.Length + sizeof(UNICODE_NULL);
  264. //
  265. // Allocate a buffer to set the reparse point.
  266. //
  267. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)LocalAlloc( LPTR,
  268. REPARSE_DATA_BUFFER_HEADER_SIZE +
  269. ReparseDataLength
  270. );
  271. if (ReparseBufferHeader == NULL) {
  272. CloseHandle( Handle );
  273. errmsg( "Unable to allocate reparse buffer", GetLastError() );
  274. return FALSE;
  275. }
  276. ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  277. ReparseBufferHeader->ReparseDataLength = (USHORT)ReparseDataLength;
  278. ReparseBufferHeader->Reserved = 0;
  279. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
  280. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength = UnicodeNameB.Length;
  281. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset = UnicodeNameB.Length + sizeof( UNICODE_NULL );
  282. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength = DosNameB.Length;
  283. RtlCopyMemory(
  284. ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer,
  285. UnicodeNameB.Buffer,
  286. UnicodeNameB.Length
  287. );
  288. RtlCopyMemory(
  289. (PCHAR)(ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer)+
  290. UnicodeNameB.Length + sizeof(UNICODE_NULL),
  291. DosNameB.Buffer,
  292. DosNameB.Length
  293. );
  294. Status = NtFsControlFile(
  295. Handle,
  296. NULL,
  297. NULL,
  298. NULL,
  299. &IoStatusBlock,
  300. FSCTL_SET_REPARSE_POINT,
  301. ReparseBufferHeader,
  302. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseBufferHeader->ReparseDataLength,
  303. NULL, // no output buffer
  304. 0 // output buffer length
  305. );
  306. LocalFree( (HLOCAL)ReparseBufferHeader );
  307. CloseHandle( Handle );
  308. if (!NT_SUCCESS(Status)) {
  309. switch( Status ) {
  310. case STATUS_VOLUME_NOT_UPGRADED:
  311. case STATUS_INVALID_DEVICE_REQUEST:
  312. printf( "%ws must be on an NT5 NTFS volume.\n", DirA );
  313. break;
  314. default:
  315. printf( "Unable to set reparse point data, status %X", Status );
  316. break;
  317. }
  318. return FALSE;
  319. }
  320. return TRUE;
  321. }
  322. //
  323. // Create the system volume subtree
  324. //
  325. BOOLEAN
  326. CreateSysVolTree( LPWSTR SysVolPath, BOOLEAN IsFirstDCInDomain , PWCHAR domainName)
  327. {
  328. DWORD i;
  329. WCHAR bufA[ MAX_PATH ];
  330. WCHAR bufB[ MAX_PATH ];
  331. printf( "Checking %ws subtree at %ws\n", SysVolShare, SysVolPath );
  332. if( !EnsureDirectoryExists( SysVolPath) ) {
  333. return FALSE;
  334. }
  335. //
  336. // First create the static system volume directories
  337. //
  338. for( i = 0; StaticSysvolDirs[i]; i++ ) {
  339. wcscpy( bufA, SysVolPath );
  340. wcscat( bufA, L"\\" );
  341. wcscat( bufA, StaticSysvolDirs[i] );
  342. if( !EnsureDirectoryExists( bufA ) ) {
  343. return FALSE;
  344. }
  345. }
  346. //
  347. // Create the DNS domain link for the sysvol share
  348. //
  349. wcscpy( bufA, SysVolPath );
  350. wcscat( bufA, L"\\sysvol\\" );
  351. wcscat( bufA, domainName );
  352. wcscpy( bufB, SysVolPath );
  353. wcscat( bufB, L"\\domain" );
  354. if( !LinkAToB( bufA, bufB ) ) {
  355. return FALSE;
  356. }
  357. //
  358. // Create the enterprise link for the sysvol share
  359. //
  360. wcscpy( bufA, SysVolPath );
  361. wcscat( bufA, L"\\sysvol\\enterprise" );
  362. wcscpy( bufB, SysVolPath );
  363. wcscat( bufB, L"\\enterprise" );
  364. if( !LinkAToB( bufA, bufB ) ) {
  365. return FALSE;
  366. }
  367. //
  368. // Create the DNS domain link in the staging area
  369. //
  370. wcscpy( bufA, SysVolPath );
  371. wcscat( bufA, L"\\staging areas\\" );
  372. wcscat( bufA, domainName );
  373. wcscpy( bufB, SysVolPath );
  374. wcscat( bufB, L"\\staging\\domain" );
  375. if( !LinkAToB( bufA, bufB ) ) {
  376. return FALSE;
  377. }
  378. //
  379. // Create the enterprise link in the staging area
  380. //
  381. wcscpy( bufA, SysVolPath );
  382. wcscat( bufA, L"\\staging areas\\enterprise" );
  383. wcscpy( bufB, SysVolPath );
  384. wcscat( bufB, L"\\staging\\enterprise" );
  385. if( !LinkAToB( bufA, bufB ) ) {
  386. return FALSE;
  387. }
  388. //
  389. // Finally, if we are the first DC initialized in this domain,
  390. // we need to create the scripts directory
  391. //
  392. if( IsFirstDCInDomain ) {
  393. wcscpy( bufA, SysVolPath );
  394. wcscat( bufA, L"\\domain\\scripts" );
  395. if( !EnsureDirectoryExists( bufA ) ) {
  396. return FALSE;
  397. }
  398. }
  399. return TRUE;
  400. }
  401. //
  402. // Create the system volume share.
  403. //
  404. BOOLEAN
  405. CreateSysVolShare( LPWSTR SysVolPath )
  406. {
  407. DWORD dwType, retval;
  408. SHARE_INFO_2 si2, *psi2;
  409. printf( "Creating system volume share:\n" );
  410. //
  411. // Blow away the current sysvol share if it exists
  412. //
  413. retval = NetShareGetInfo( NULL, SysVolShare, 2, (LPBYTE *)&psi2 );
  414. if( retval == NO_ERROR ) {
  415. if( psi2->shi2_type != STYPE_DISKTREE ) {
  416. fprintf( stderr, "%ws is shared, but is not a disk share!\n" );
  417. return FALSE;
  418. }
  419. printf( " Delete current share: %ws=%ws\n", psi2->shi2_netname, psi2->shi2_path );
  420. NetApiBufferFree( psi2 );
  421. //
  422. // Try to delete this share
  423. //
  424. retval = NetShareDel( NULL, SysVolShare, 0 );
  425. if( retval != NO_ERROR ) {
  426. errmsg( "Unable to delete sysvol share", retval );
  427. return FALSE;
  428. }
  429. }
  430. //
  431. // Add the new sysvol share
  432. //
  433. si2.shi2_netname = SysVolShare;
  434. si2.shi2_type = STYPE_DISKTREE;
  435. si2.shi2_remark = SysVolRemark;
  436. si2.shi2_permissions = 0;
  437. si2.shi2_max_uses = (DWORD)-1;
  438. si2.shi2_current_uses = 0;
  439. si2.shi2_path = SysVolPath;
  440. si2.shi2_passwd = 0;
  441. printf( " Add share: %ws=%ws\n", SysVolShare, SysVolPath );
  442. retval = NetShareAdd( NULL, 2, (LPBYTE)&si2, &dwType );
  443. if( retval != NO_ERROR ) {
  444. errmsg( "Unable to share new sysvol share", retval );
  445. return FALSE;
  446. }
  447. //
  448. // Add the registry key telling netlogon to share this out as the system volume share
  449. //
  450. printf( " Add netlogon sysvol registry key\n" );
  451. return WriteRegistry( L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters",
  452. L"SysVol",
  453. SysVolPath
  454. );
  455. }
  456. //
  457. // Add the registry keys needed for NTFRS. Do what DcPromo would have done
  458. //
  459. BOOLEAN
  460. AddRegKeys(
  461. IN PWCHAR ReplicaSetName,
  462. IN PWCHAR ReplicaSetType,
  463. IN DWORD ReplicaSetPrimary,
  464. IN PWCHAR ReplicaSetStage,
  465. IN PWCHAR ReplicaSetRoot )
  466. {
  467. WCHAR KeyName[512];
  468. //
  469. // Make sure the NTFRS section is there
  470. //
  471. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  472. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  473. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  474. //
  475. // Sysvol key + values
  476. //
  477. wcscpy( KeyName, L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol\\" );
  478. wcscat( KeyName, ReplicaSetName );
  479. WriteRegistry( KeyName, DSROLEP_FRS_COMMAND, DSROLEP_FRS_CREATE );
  480. WriteRegistry( KeyName, DSROLEP_FRS_NAME, ReplicaSetName );
  481. WriteRegistry( KeyName, DSROLEP_FRS_TYPE, ReplicaSetType );
  482. WriteRegistry( KeyName, DSROLEP_FRS_PRIMARY, (DWORD)ReplicaSetPrimary );
  483. WriteRegistry( KeyName, DSROLEP_FRS_ROOT, ReplicaSetRoot );
  484. WriteRegistry( KeyName, DSROLEP_FRS_STAGE, ReplicaSetStage );
  485. return TRUE;
  486. }
  487. //
  488. // Commit the registry keys so that if NtFrs is running it can now
  489. // pick up a consistent set of values.
  490. //
  491. BOOLEAN
  492. CommitRegKeys(
  493. VOID )
  494. {
  495. //
  496. // Make sure the NTFRS section is there
  497. //
  498. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  499. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  500. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  501. //
  502. // Commit both sysvols
  503. //
  504. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol",
  505. DSROLEP_FRS_COMMITTED, (DWORD)1 );
  506. return TRUE;
  507. }
  508. //
  509. // Commit the registry keys so that if NtFrs is running it can now
  510. // pick up a consistent set of values.
  511. //
  512. BOOLEAN
  513. DeleteRegKeys(
  514. VOID )
  515. {
  516. DWORD WStatus;
  517. HKEY HKey = 0;
  518. WCHAR KeyBuf[MAX_PATH + 1];
  519. printf("Delete registry keys.\n");
  520. //
  521. // Make sure the NTFRS section is there
  522. //
  523. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  524. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  525. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  526. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  527. L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol",
  528. 0,
  529. KEY_ALL_ACCESS,
  530. &HKey);
  531. if (WStatus != ERROR_SUCCESS) {
  532. errmsg("Cannot open registry", WStatus);
  533. return FALSE;
  534. }
  535. WStatus = RegDeleteValue(HKey, DSROLEP_FRS_COMMITTED);
  536. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_FILE_NOT_FOUND) {
  537. errmsg("Cannot delete registry value", WStatus);
  538. return FALSE;
  539. }
  540. //
  541. // Delete the subkeys
  542. //
  543. do {
  544. WStatus = RegEnumKey(HKey, 0, KeyBuf, MAX_PATH + 1);
  545. if (WStatus == ERROR_SUCCESS) {
  546. WStatus = RegDeleteKey(HKey, KeyBuf);
  547. }
  548. } while (WStatus == ERROR_SUCCESS);
  549. if (WStatus != ERROR_NO_MORE_ITEMS) {
  550. errmsg("Cannot delete registry key", WStatus);
  551. return FALSE;
  552. }
  553. RegCloseKey(HKey);
  554. return TRUE;
  555. }
  556. //
  557. // Set FRS to auto start
  558. //
  559. BOOLEAN
  560. SetFRSAutoStart( void )
  561. {
  562. SC_HANDLE ServiceHandle;
  563. SC_HANDLE SCMHandle;
  564. printf( "Set NTFRS to Auto Start\n" );
  565. //
  566. // Contact the SC manager.
  567. //
  568. SCMHandle = OpenSCManager(NULL,
  569. NULL,
  570. SC_MANAGER_CONNECT);
  571. if (SCMHandle == NULL) {
  572. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  573. return FALSE;
  574. }
  575. //
  576. // Contact the NtFrs service.
  577. //
  578. ServiceHandle = OpenService(SCMHandle,
  579. DSROLEP_FRS_SHORT_NAME,
  580. SERVICE_INTERROGATE |
  581. SERVICE_PAUSE_CONTINUE |
  582. SERVICE_QUERY_STATUS |
  583. SERVICE_START |
  584. SERVICE_STOP |
  585. SERVICE_CHANGE_CONFIG);
  586. if (ServiceHandle == NULL) {
  587. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  588. return FALSE;
  589. }
  590. CloseServiceHandle(SCMHandle);
  591. //
  592. // Service starts automatically at startup
  593. //
  594. if (!ChangeServiceConfig(ServiceHandle,
  595. SERVICE_NO_CHANGE,
  596. SERVICE_AUTO_START,
  597. SERVICE_NO_CHANGE,
  598. NULL,
  599. NULL,
  600. NULL,
  601. NULL,
  602. NULL,
  603. NULL,
  604. DSROLEP_FRS_LONG_NAME)) {
  605. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  606. return FALSE;
  607. }
  608. CloseServiceHandle(ServiceHandle);
  609. return TRUE;
  610. }
  611. //
  612. // Start FRS
  613. //
  614. BOOLEAN
  615. StartFRS( void )
  616. {
  617. DWORD WStatus;
  618. SC_HANDLE ServiceHandle;
  619. SC_HANDLE SCMHandle;
  620. SERVICE_STATUS ServiceStatus;
  621. printf( "Start NTFRS\n" );
  622. //
  623. // Contact the SC manager.
  624. //
  625. SCMHandle = OpenSCManager(NULL,
  626. NULL,
  627. SC_MANAGER_CONNECT);
  628. if (SCMHandle == NULL) {
  629. errmsg("Can't start NtFrs", GetLastError());
  630. return FALSE;
  631. }
  632. //
  633. // Contact the NtFrs service.
  634. //
  635. ServiceHandle = OpenService(SCMHandle,
  636. DSROLEP_FRS_SHORT_NAME,
  637. SERVICE_INTERROGATE |
  638. SERVICE_PAUSE_CONTINUE |
  639. SERVICE_QUERY_STATUS |
  640. SERVICE_START |
  641. SERVICE_STOP |
  642. SERVICE_CHANGE_CONFIG);
  643. if (ServiceHandle == NULL) {
  644. errmsg("Can't start NtFrs", GetLastError());
  645. return FALSE;
  646. }
  647. CloseServiceHandle(SCMHandle);
  648. //
  649. // stop the service
  650. //
  651. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  652. //
  653. // Start the service
  654. //
  655. if (!StartService(ServiceHandle, 0, NULL)) {
  656. //
  657. // May be shutting down; retry in a bit
  658. //
  659. Sleep(3 * 1000);
  660. if (!StartService(ServiceHandle, 0, NULL)) {
  661. WStatus = GetLastError();
  662. if (WStatus != ERROR_SERVICE_ALREADY_RUNNING) {
  663. errmsg("Can't start NtFrs", WStatus);
  664. return FALSE;
  665. }
  666. }
  667. }
  668. CloseServiceHandle(ServiceHandle);
  669. return TRUE;
  670. }
  671. BOOLEAN
  672. IsThisADC(
  673. IN PWCHAR domainName )
  674. {
  675. DWORD WStatus;
  676. PWCHAR p;
  677. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *DsRole;
  678. //
  679. // Is this a domain controller?
  680. //
  681. WStatus = DsRoleGetPrimaryDomainInformation(NULL,
  682. DsRolePrimaryDomainInfoBasic,
  683. (PBYTE *)&DsRole);
  684. if (WStatus != ERROR_SUCCESS) {
  685. errmsg("Can't get primary domain information", WStatus);
  686. return FALSE;
  687. }
  688. //
  689. // Domain Controller (DC)
  690. //
  691. if (DsRole->MachineRole == DsRole_RoleBackupDomainController ||
  692. DsRole->MachineRole == DsRole_RolePrimaryDomainController) {
  693. if (!DsRole->DomainNameDns) {
  694. errmsg( "Unable to get domain name", ERROR_PATH_NOT_FOUND );
  695. return FALSE;
  696. }
  697. wcscpy(domainName, DsRole->DomainNameDns);
  698. DsRoleFreeMemory(DsRole);
  699. for( p = domainName; *p != L'\0'; p++ );
  700. if( *(p-1) == L'.' ) {
  701. *(p-1) = L'\0';
  702. }
  703. return TRUE;
  704. }
  705. DsRoleFreeMemory(DsRole);
  706. return FALSE;
  707. }
  708. /*
  709. * Make it so NTFRS will run on this DC
  710. */
  711. __cdecl
  712. main( int argc, char *argv[] )
  713. {
  714. DWORD i;
  715. LONG retval;
  716. BOOLEAN IsFirstDCInDomain = FALSE;
  717. BOOLEAN IsFirstDCInEnterprise = FALSE;
  718. WCHAR SysVolPath[ MAX_PATH ], stage[ MAX_PATH ], root[ MAX_PATH ];
  719. DWORD pathType;
  720. WCHAR domainName[512];
  721. SysVolPath[0] = 0;
  722. if( IsThisADC( domainName ) == FALSE ) {
  723. fprintf( stderr, "This program can only be run on a DC!\n" );
  724. return 1;
  725. }
  726. for( i = 1; i < (DWORD)argc; i++ ) {
  727. switch( argv[i][0] ) {
  728. case '/':
  729. case '-':
  730. switch( argv[i][1] ) {
  731. case 'D':
  732. case 'd':
  733. IsFirstDCInDomain = TRUE;
  734. break;
  735. case 'E':
  736. case 'e':
  737. IsFirstDCInEnterprise = TRUE;
  738. IsFirstDCInDomain = TRUE;
  739. break;
  740. default:
  741. fprintf( stderr, "Unrecognized option: %c\n\n", argv[i][1] );
  742. Usage( argc, argv );
  743. return 1;
  744. }
  745. break;
  746. default:
  747. if( SysVolPath[0] != 0 ) {
  748. fprintf( stderr, "Too many 'sysvol' paths! Need quotes?\n\n" );
  749. Usage( argc, argv );
  750. return 1;
  751. }
  752. mbstowcs( SysVolPath, argv[i], sizeof( SysVolPath ) );
  753. //
  754. // Make sure the system volume path is reasonable
  755. //
  756. retval = NetpPathType( NULL, SysVolPath, &pathType, 0 );
  757. if( retval != NO_ERROR || pathType != ITYPE_PATH_ABSD ) {
  758. fprintf( stderr, "Invalid system volume path. Must be an absolute path.\n" );
  759. return 1;
  760. }
  761. break;
  762. }
  763. }
  764. if( SysVolPath[0] == 0 ) {
  765. Usage( argc, argv );
  766. return 1;
  767. }
  768. printf( "Initializing the NT MultiMaster File Replication Service:\n" );
  769. printf( " Domain: %ws\n", domainName );
  770. if( IsFirstDCInDomain ) {
  771. printf( " First DC in the domain\n" );
  772. }
  773. if( IsFirstDCInEnterprise ) {
  774. printf( " First DC in the enterprise\n" );
  775. }
  776. printf( " System Volume: %ws\n", SysVolPath );
  777. //
  778. // Create the sysvol tree and share it out
  779. //
  780. if( !CreateSysVolTree( SysVolPath, IsFirstDCInDomain, domainName ) ||
  781. !CreateSysVolShare( SysVolPath ) ) {
  782. return 1;
  783. }
  784. //
  785. // Add the registry keys for the NTFRS enterprise volume
  786. //
  787. wcscpy( stage, SysVolPath );
  788. wcscat( stage, L"\\staging areas\\enterprise" );
  789. wcscpy( root, SysVolPath );
  790. wcscat( root, L"\\sysvol\\enterprise" );
  791. if( !AddRegKeys( L"enterprise",
  792. L"enterprise",
  793. IsFirstDCInEnterprise,
  794. stage,
  795. root ) ) {
  796. goto errout;
  797. }
  798. //
  799. // Add the registry keys for the NTFRS domain volume
  800. //
  801. wcscpy( stage, SysVolPath );
  802. wcscat( stage, L"\\staging areas\\" );
  803. wcscat( stage, domainName );
  804. wcscpy( root, SysVolPath );
  805. wcscat( root, L"\\sysvol\\" );
  806. wcscat( root, domainName );
  807. if( !AddRegKeys( domainName,
  808. L"domain",
  809. IsFirstDCInDomain,
  810. stage,
  811. root ) ) {
  812. goto errout;
  813. }
  814. //
  815. // Commit the keys only after all of the values are set without error.
  816. // Otherwise, a running NtFrs might pick up the keys while they are in
  817. // an incomplete state.
  818. //
  819. if( !CommitRegKeys()) {
  820. goto errout;
  821. }
  822. //
  823. // Now ensure that the replication service is running, and will run at each boot
  824. //
  825. if( !SetFRSAutoStart() || !StartFRS() ) {
  826. goto errout;
  827. }
  828. printf( "Success!\n" );
  829. return 0;
  830. errout:
  831. fprintf( stderr, "Warning: SYSVOL share path may have been changed.\n" );
  832. return 1;
  833. }