|
|
extern "C" { #include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntioapi.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <lm.h>
#include <netcan.h>
#include <icanon.h>
#include <dsgetdc.h>
#include <dsrole.h>
}
/*
* This program performs the steps necessary to configure NTFRS on a DC, prepared * to support the system and enterprise volumes. * * It was created as an interim tool to support the initialization of NTFRS on a DC * which was running NT5 generation software before NTFRS was available. After upgrading * that DC with the latest NT5 version, this tool must be manually run to complete the * initialization of NTFRS and system volumes. */
WCHAR SysVolShare[] = L"SYSVOL"; WCHAR SysVolRemark[] = L"System Volume Share (Migrated)"; WCHAR FRSSysvol[] = L"System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Sysvol";
#define DSROLEP_FRS_COMMAND L"Replica Set Command"
#define DSROLEP_FRS_NAME L"Replica Set Name"
#define DSROLEP_FRS_TYPE L"Replica Set Type"
#define DSROLEP_FRS_PRIMARY L"Replica Set Primary"
#define DSROLEP_FRS_STAGE L"Replica Set Stage"
#define DSROLEP_FRS_ROOT L"Replica Set Root"
#define DSROLEP_FRS_CREATE L"Create"
#define DSROLEP_FRS_DELETE L"Delete"
#define DSROLEP_FRS_COMMITTED L"SysVol Information is Committed"
#define DSROLEP_FRS_LONG_NAME L"Microsoft File Replication Service"
#define DSROLEP_FRS_SHORT_NAME L"NtFrs"
//
// These are the static directories created within a system volume share
//
LPWSTR StaticSysvolDirs[] = { L"sysvol", L"domain", L"enterprise", L"staging", L"staging areas",
L"sysvol\\enterprise", L"staging\\domain", L"staging\\enterprise", 0 };
//
// Print out the usage message
//
void Usage( int argc, char *argv[] ) { fprintf( stderr, "Usage: %s [-D] [-E] sysvol\n\n", argv[0] ); fprintf( stderr, " -D this is the first upgraded DC in this domain\n\n" ); fprintf( stderr, " -E this is the first upgraded DC in this enterprise\n\n" ); fprintf( stderr, " sysvol is the path for the system volume share.\n" ); fprintf( stderr, " The system volume must reside on NTFS version 5\n" ); }
//
// Print 'text' and render 'code' into an error message
//
void errmsg( char *text, ULONG code ) { int i; char msg[ 100 ];
i = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ), NULL, code, 0, msg, sizeof(msg), NULL );
if( i ) fprintf( stderr, "%s: %s\n", text ? text : "", msg ); else fprintf( stderr, "%s: error %d\n", text ? text : "", code ); }
//
// Print unicode 'text' and render 'code' into an error message
//
void errmsg( LPWSTR text, ULONG code ) { int i; WCHAR msg[ 100 ];
i = FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ), NULL, code, 0, msg, sizeof(msg), NULL );
if( i ) fprintf( stderr, "%ws: %ws\n", text ? text : L"", msg ); else fprintf( stderr, "%ws: error %d\n", text ? text : L"", code ); }
//
// Write a string value to the registry
//
BOOLEAN WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, LPWSTR Value ) { HKEY hKey; DWORD disposition; LONG retval;
//
// First ensure that 'keyname' exists in the registry
//
retval = RegCreateKeyEx( HKEY_LOCAL_MACHINE, KeyName, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &disposition );
if( retval != ERROR_SUCCESS ) { errmsg( KeyName, retval ); return FALSE; }
if( ARGUMENT_PRESENT( ValueName ) ) {
retval = RegSetValueEx( hKey, ValueName, 0, REG_SZ, (BYTE *)Value, (wcslen( Value ) + 1) * sizeof( WCHAR ) );
if( retval != ERROR_SUCCESS ) { errmsg( ValueName, retval ); RegCloseKey( hKey ); return FALSE; } }
RegCloseKey( hKey ); return TRUE; }
//
// Write a DWORD value to the registry
//
BOOLEAN WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, DWORD Value ) { HKEY hKey; DWORD disposition; LONG retval;
//
// First ensure that 'keyname' exists in the registry
//
retval = RegCreateKeyEx( HKEY_LOCAL_MACHINE, KeyName, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &disposition );
if( retval != ERROR_SUCCESS ) { errmsg( KeyName, retval ); return FALSE; }
if( ARGUMENT_PRESENT( ValueName ) ) {
retval = RegSetValueEx( hKey, ValueName, 0, REG_DWORD, (BYTE *)&Value, sizeof( Value ) );
if( retval != ERROR_SUCCESS ) { errmsg( ValueName, retval ); RegCloseKey( hKey ); return FALSE; } }
RegCloseKey( hKey ); return TRUE; }
//
// Make sure that 'DirName' exists. Create it if it doesn't
//
BOOLEAN EnsureDirectoryExists( LPWSTR DirName ) { DWORD retval;
retval = GetFileAttributes( DirName );
if( retval == 0xFFFFFFFF ) { printf( " Create directory: %ws\n", DirName ); if( !CreateDirectory( DirName, NULL ) ) { retval = GetLastError(); errmsg( DirName, GetLastError() ); return FALSE; } } else if( !(retval & FILE_ATTRIBUTE_DIRECTORY) ) { fprintf( stderr, "Not a directory: %ws\n", DirName ); return FALSE; }
return TRUE; }
BOOLEAN LinkAToB( LPWSTR DirA, LPWSTR DirB ) { NTSTATUS Status; HANDLE Handle; UNICODE_STRING UnicodeNameB; UNICODE_STRING DosNameB; IO_STATUS_BLOCK IoStatusBlock; PREPARSE_DATA_BUFFER ReparseBufferHeader; PCHAR ReparseBuffer; USHORT ReparseDataLength;
if( !EnsureDirectoryExists( DirA ) || !EnsureDirectoryExists( DirB ) ) {
return FALSE; }
Handle = CreateFile( DirA, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL );
if( Handle == INVALID_HANDLE_VALUE ) { fprintf( stderr, "Unable to open %ws", DirA ); errmsg( (LPWSTR)NULL, GetLastError() ); return FALSE; }
//
// Get the NT path name of the directory to which we want to link
//
if( !RtlDosPathNameToNtPathName_U( DirB, &UnicodeNameB, NULL, NULL )) { errmsg( DirB, GetLastError() ); return FALSE; } RtlInitUnicodeString( &DosNameB, DirB);
//
// Set the reparse point with mount point or symbolic link tag and determine
// the appropriate length of the buffer.
//
ReparseDataLength = (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - REPARSE_DATA_BUFFER_HEADER_SIZE) + UnicodeNameB.Length + sizeof(UNICODE_NULL) + DosNameB.Length + sizeof(UNICODE_NULL);
//
// Allocate a buffer to set the reparse point.
//
ReparseBufferHeader = (PREPARSE_DATA_BUFFER)LocalAlloc( LPTR, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataLength );
if (ReparseBufferHeader == NULL) { CloseHandle( Handle ); errmsg( "Unable to allocate reparse buffer", GetLastError() ); return FALSE; }
ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; ReparseBufferHeader->ReparseDataLength = (USHORT)ReparseDataLength; ReparseBufferHeader->Reserved = 0;
ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0; ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength = UnicodeNameB.Length; ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset = UnicodeNameB.Length + sizeof( UNICODE_NULL ); ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength = DosNameB.Length; RtlCopyMemory( ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer, UnicodeNameB.Buffer, UnicodeNameB.Length ); RtlCopyMemory( (PCHAR)(ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer)+ UnicodeNameB.Length + sizeof(UNICODE_NULL), DosNameB.Buffer, DosNameB.Length );
Status = NtFsControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_SET_REPARSE_POINT, ReparseBufferHeader, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseBufferHeader->ReparseDataLength, NULL, // no output buffer
0 // output buffer length
);
LocalFree( (HLOCAL)ReparseBufferHeader );
CloseHandle( Handle );
if (!NT_SUCCESS(Status)) {
switch( Status ) { case STATUS_VOLUME_NOT_UPGRADED: case STATUS_INVALID_DEVICE_REQUEST: printf( "%ws must be on an NT5 NTFS volume.\n", DirA ); break;
default: printf( "Unable to set reparse point data, status %X", Status ); break; }
return FALSE; }
return TRUE; }
//
// Create the system volume subtree
//
BOOLEAN CreateSysVolTree( LPWSTR SysVolPath, BOOLEAN IsFirstDCInDomain , PWCHAR domainName) { DWORD i; WCHAR bufA[ MAX_PATH ]; WCHAR bufB[ MAX_PATH ];
printf( "Checking %ws subtree at %ws\n", SysVolShare, SysVolPath );
if( !EnsureDirectoryExists( SysVolPath) ) { return FALSE; }
//
// First create the static system volume directories
//
for( i = 0; StaticSysvolDirs[i]; i++ ) { wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\" ); wcscat( bufA, StaticSysvolDirs[i] );
if( !EnsureDirectoryExists( bufA ) ) { return FALSE; } }
//
// Create the DNS domain link for the sysvol share
//
wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\sysvol\\" ); wcscat( bufA, domainName );
wcscpy( bufB, SysVolPath ); wcscat( bufB, L"\\domain" );
if( !LinkAToB( bufA, bufB ) ) { return FALSE; }
//
// Create the enterprise link for the sysvol share
//
wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\sysvol\\enterprise" );
wcscpy( bufB, SysVolPath ); wcscat( bufB, L"\\enterprise" );
if( !LinkAToB( bufA, bufB ) ) { return FALSE; }
//
// Create the DNS domain link in the staging area
//
wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\staging areas\\" ); wcscat( bufA, domainName );
wcscpy( bufB, SysVolPath ); wcscat( bufB, L"\\staging\\domain" );
if( !LinkAToB( bufA, bufB ) ) { return FALSE; }
//
// Create the enterprise link in the staging area
//
wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\staging areas\\enterprise" );
wcscpy( bufB, SysVolPath ); wcscat( bufB, L"\\staging\\enterprise" );
if( !LinkAToB( bufA, bufB ) ) { return FALSE; }
//
// Finally, if we are the first DC initialized in this domain,
// we need to create the scripts directory
//
if( IsFirstDCInDomain ) {
wcscpy( bufA, SysVolPath ); wcscat( bufA, L"\\domain\\scripts" );
if( !EnsureDirectoryExists( bufA ) ) { return FALSE; } }
return TRUE; }
//
// Create the system volume share.
//
BOOLEAN CreateSysVolShare( LPWSTR SysVolPath ) { DWORD dwType, retval; SHARE_INFO_2 si2, *psi2;
printf( "Creating system volume share:\n" );
//
// Blow away the current sysvol share if it exists
//
retval = NetShareGetInfo( NULL, SysVolShare, 2, (LPBYTE *)&psi2 );
if( retval == NO_ERROR ) { if( psi2->shi2_type != STYPE_DISKTREE ) { fprintf( stderr, "%ws is shared, but is not a disk share!\n" ); return FALSE; }
printf( " Delete current share: %ws=%ws\n", psi2->shi2_netname, psi2->shi2_path );
NetApiBufferFree( psi2 );
//
// Try to delete this share
//
retval = NetShareDel( NULL, SysVolShare, 0 ); if( retval != NO_ERROR ) { errmsg( "Unable to delete sysvol share", retval ); return FALSE; } }
//
// Add the new sysvol share
//
si2.shi2_netname = SysVolShare; si2.shi2_type = STYPE_DISKTREE; si2.shi2_remark = SysVolRemark; si2.shi2_permissions = 0; si2.shi2_max_uses = (DWORD)-1; si2.shi2_current_uses = 0; si2.shi2_path = SysVolPath; si2.shi2_passwd = 0;
printf( " Add share: %ws=%ws\n", SysVolShare, SysVolPath ); retval = NetShareAdd( NULL, 2, (LPBYTE)&si2, &dwType );
if( retval != NO_ERROR ) { errmsg( "Unable to share new sysvol share", retval ); return FALSE; }
//
// Add the registry key telling netlogon to share this out as the system volume share
//
printf( " Add netlogon sysvol registry key\n" );
return WriteRegistry( L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters", L"SysVol", SysVolPath ); }
//
// Add the registry keys needed for NTFRS. Do what DcPromo would have done
//
BOOLEAN AddRegKeys( IN PWCHAR ReplicaSetName, IN PWCHAR ReplicaSetType, IN DWORD ReplicaSetPrimary, IN PWCHAR ReplicaSetStage, IN PWCHAR ReplicaSetRoot ) { WCHAR KeyName[512];
//
// Make sure the NTFRS section is there
//
WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
//
// Sysvol key + values
//
wcscpy( KeyName, L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol\\" ); wcscat( KeyName, ReplicaSetName ); WriteRegistry( KeyName, DSROLEP_FRS_COMMAND, DSROLEP_FRS_CREATE ); WriteRegistry( KeyName, DSROLEP_FRS_NAME, ReplicaSetName ); WriteRegistry( KeyName, DSROLEP_FRS_TYPE, ReplicaSetType ); WriteRegistry( KeyName, DSROLEP_FRS_PRIMARY, (DWORD)ReplicaSetPrimary ); WriteRegistry( KeyName, DSROLEP_FRS_ROOT, ReplicaSetRoot ); WriteRegistry( KeyName, DSROLEP_FRS_STAGE, ReplicaSetStage );
return TRUE; }
//
// Commit the registry keys so that if NtFrs is running it can now
// pick up a consistent set of values.
//
BOOLEAN CommitRegKeys( VOID ) { //
// Make sure the NTFRS section is there
//
WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
//
// Commit both sysvols
//
WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", DSROLEP_FRS_COMMITTED, (DWORD)1 ); return TRUE; }
//
// Commit the registry keys so that if NtFrs is running it can now
// pick up a consistent set of values.
//
BOOLEAN DeleteRegKeys( VOID ) { DWORD WStatus; HKEY HKey = 0; WCHAR KeyBuf[MAX_PATH + 1];
printf("Delete registry keys.\n");
//
// Make sure the NTFRS section is there
//
WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 ); WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, KEY_ALL_ACCESS, &HKey); if (WStatus != ERROR_SUCCESS) { errmsg("Cannot open registry", WStatus); return FALSE; } WStatus = RegDeleteValue(HKey, DSROLEP_FRS_COMMITTED); if (WStatus != ERROR_SUCCESS && WStatus != ERROR_FILE_NOT_FOUND) { errmsg("Cannot delete registry value", WStatus); return FALSE; } //
// Delete the subkeys
//
do { WStatus = RegEnumKey(HKey, 0, KeyBuf, MAX_PATH + 1); if (WStatus == ERROR_SUCCESS) { WStatus = RegDeleteKey(HKey, KeyBuf); } } while (WStatus == ERROR_SUCCESS); if (WStatus != ERROR_NO_MORE_ITEMS) { errmsg("Cannot delete registry key", WStatus); return FALSE; } RegCloseKey(HKey); return TRUE; }
//
// Set FRS to auto start
//
BOOLEAN SetFRSAutoStart( void ) { SC_HANDLE ServiceHandle; SC_HANDLE SCMHandle;
printf( "Set NTFRS to Auto Start\n" );
//
// Contact the SC manager.
//
SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (SCMHandle == NULL) { errmsg("Can't set NtFrs to Auto Start", GetLastError()); return FALSE; }
//
// Contact the NtFrs service.
//
ServiceHandle = OpenService(SCMHandle, DSROLEP_FRS_SHORT_NAME, SERVICE_INTERROGATE | SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG); if (ServiceHandle == NULL) { errmsg("Can't set NtFrs to Auto Start", GetLastError()); return FALSE; } CloseServiceHandle(SCMHandle);
//
// Service starts automatically at startup
//
if (!ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, DSROLEP_FRS_LONG_NAME)) { errmsg("Can't set NtFrs to Auto Start", GetLastError()); return FALSE; } CloseServiceHandle(ServiceHandle); return TRUE; }
//
// Start FRS
//
BOOLEAN StartFRS( void ) { DWORD WStatus; SC_HANDLE ServiceHandle; SC_HANDLE SCMHandle; SERVICE_STATUS ServiceStatus;
printf( "Start NTFRS\n" );
//
// Contact the SC manager.
//
SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (SCMHandle == NULL) { errmsg("Can't start NtFrs", GetLastError()); return FALSE; }
//
// Contact the NtFrs service.
//
ServiceHandle = OpenService(SCMHandle, DSROLEP_FRS_SHORT_NAME, SERVICE_INTERROGATE | SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG); if (ServiceHandle == NULL) { errmsg("Can't start NtFrs", GetLastError()); return FALSE; } CloseServiceHandle(SCMHandle);
//
// stop the service
//
ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
//
// Start the service
//
if (!StartService(ServiceHandle, 0, NULL)) { //
// May be shutting down; retry in a bit
//
Sleep(3 * 1000); if (!StartService(ServiceHandle, 0, NULL)) { WStatus = GetLastError(); if (WStatus != ERROR_SERVICE_ALREADY_RUNNING) { errmsg("Can't start NtFrs", WStatus); return FALSE; } } } CloseServiceHandle(ServiceHandle); return TRUE; }
BOOLEAN IsThisADC( IN PWCHAR domainName ) { DWORD WStatus; PWCHAR p; DSROLE_PRIMARY_DOMAIN_INFO_BASIC *DsRole;
//
// Is this a domain controller?
//
WStatus = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&DsRole); if (WStatus != ERROR_SUCCESS) { errmsg("Can't get primary domain information", WStatus); return FALSE; }
//
// Domain Controller (DC)
//
if (DsRole->MachineRole == DsRole_RoleBackupDomainController || DsRole->MachineRole == DsRole_RolePrimaryDomainController) { if (!DsRole->DomainNameDns) { errmsg( "Unable to get domain name", ERROR_PATH_NOT_FOUND ); return FALSE; } wcscpy(domainName, DsRole->DomainNameDns); DsRoleFreeMemory(DsRole); for( p = domainName; *p != L'\0'; p++ ); if( *(p-1) == L'.' ) { *(p-1) = L'\0'; } return TRUE; } DsRoleFreeMemory(DsRole); return FALSE; }
/*
* Make it so NTFRS will run on this DC */ __cdecl main( int argc, char *argv[] ) { DWORD i; LONG retval; BOOLEAN IsFirstDCInDomain = FALSE; BOOLEAN IsFirstDCInEnterprise = FALSE; WCHAR SysVolPath[ MAX_PATH ], stage[ MAX_PATH ], root[ MAX_PATH ]; DWORD pathType; WCHAR domainName[512];
SysVolPath[0] = 0;
if( IsThisADC( domainName ) == FALSE ) { fprintf( stderr, "This program can only be run on a DC!\n" ); return 1; }
for( i = 1; i < (DWORD)argc; i++ ) { switch( argv[i][0] ) { case '/': case '-': switch( argv[i][1] ) { case 'D': case 'd': IsFirstDCInDomain = TRUE; break; case 'E': case 'e': IsFirstDCInEnterprise = TRUE; IsFirstDCInDomain = TRUE; break; default: fprintf( stderr, "Unrecognized option: %c\n\n", argv[i][1] ); Usage( argc, argv ); return 1; } break; default:
if( SysVolPath[0] != 0 ) { fprintf( stderr, "Too many 'sysvol' paths! Need quotes?\n\n" ); Usage( argc, argv ); return 1; }
mbstowcs( SysVolPath, argv[i], sizeof( SysVolPath ) );
//
// Make sure the system volume path is reasonable
//
retval = NetpPathType( NULL, SysVolPath, &pathType, 0 );
if( retval != NO_ERROR || pathType != ITYPE_PATH_ABSD ) { fprintf( stderr, "Invalid system volume path. Must be an absolute path.\n" ); return 1; }
break; } }
if( SysVolPath[0] == 0 ) { Usage( argc, argv ); return 1; }
printf( "Initializing the NT MultiMaster File Replication Service:\n" ); printf( " Domain: %ws\n", domainName );
if( IsFirstDCInDomain ) { printf( " First DC in the domain\n" ); } if( IsFirstDCInEnterprise ) { printf( " First DC in the enterprise\n" ); } printf( " System Volume: %ws\n", SysVolPath );
//
// Create the sysvol tree and share it out
//
if( !CreateSysVolTree( SysVolPath, IsFirstDCInDomain, domainName ) || !CreateSysVolShare( SysVolPath ) ) {
return 1; }
//
// Add the registry keys for the NTFRS enterprise volume
//
wcscpy( stage, SysVolPath ); wcscat( stage, L"\\staging areas\\enterprise" );
wcscpy( root, SysVolPath ); wcscat( root, L"\\sysvol\\enterprise" );
if( !AddRegKeys( L"enterprise", L"enterprise", IsFirstDCInEnterprise, stage, root ) ) { goto errout; }
//
// Add the registry keys for the NTFRS domain volume
//
wcscpy( stage, SysVolPath ); wcscat( stage, L"\\staging areas\\" ); wcscat( stage, domainName );
wcscpy( root, SysVolPath ); wcscat( root, L"\\sysvol\\" ); wcscat( root, domainName );
if( !AddRegKeys( domainName, L"domain", IsFirstDCInDomain, stage, root ) ) { goto errout; }
//
// Commit the keys only after all of the values are set without error.
// Otherwise, a running NtFrs might pick up the keys while they are in
// an incomplete state.
//
if( !CommitRegKeys()) { goto errout; }
//
// Now ensure that the replication service is running, and will run at each boot
//
if( !SetFRSAutoStart() || !StartFRS() ) { goto errout; }
printf( "Success!\n" );
return 0;
errout: fprintf( stderr, "Warning: SYSVOL share path may have been changed.\n" ); return 1; }
|