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.
577 lines
18 KiB
577 lines
18 KiB
extern "C" {
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <shellapi.h>
|
|
}
|
|
#include <ole2.h>
|
|
#include <activeds.h>
|
|
#include <dfsprefix.h>
|
|
#include <DfsServerLibrary.hxx>
|
|
#include <DfsRegStrings.hxx>
|
|
#include <dfsutil.hxx>
|
|
#include <dfsmisc.h>
|
|
#include <dfspathname.hxx>
|
|
#include <struct.hxx>
|
|
|
|
LPWSTR UtilRegistryHostLocation = DFS_REG_HOST_LOCATION;
|
|
LPWSTR UtilVolumesLocation = DFS_REG_VOLUMES_LOCATION;
|
|
LPWSTR UtilFtDfsConfigDNValueName = DFS_REG_FT_DFS_CONFIG_DN_VALUE;
|
|
|
|
LPWSTR DfsHostLastDomainValueName = DFS_REG_HOST_LAST_DOMAIN_VALUE;
|
|
LPWSTR DfsDriverLocalVolumesLocation = DFS_REG_LOCAL_VOLUMES_LOCATION;
|
|
LPWSTR DfsDriverLocalVolumesEntryPath = DFS_REG_ENTRY_PATH;
|
|
LPWSTR DfsDriverLocalVolumesShortEntryPath = DFS_REG_SHORT_ENTRY_PATH;
|
|
|
|
DFSSTATUS
|
|
DfsFixupRegistryValues(
|
|
IN LPWSTR DfsPathString,
|
|
IN LPWSTR RootName,
|
|
IN LPWSTR OldDomainName,
|
|
IN LPWSTR NewDomainName);
|
|
|
|
DFSSTATUS
|
|
DfsRenameRegistries(
|
|
IN DfsPathName *pPathName,
|
|
IN LPWSTR OldDomainName,
|
|
IN LPWSTR NewDomainName);
|
|
|
|
DFSSTATUS
|
|
GetCurrentRegDomainName(
|
|
IN HKEY VolumeKey,
|
|
IN LPWSTR DfsHostValueName,
|
|
OUT LPWSTR *pValueString);
|
|
|
|
DFSSTATUS
|
|
DfsSetRegDomainName(
|
|
IN const HKEY DfsKey,
|
|
IN const LPWSTR RegValueName,
|
|
IN const LPWSTR DomainString);
|
|
|
|
BOOLEAN
|
|
DfsRenameFTConfigValueName(
|
|
IN LPWSTR DNString,
|
|
IN LPWSTR NewDomainString,
|
|
IN PUNICODE_STRING OldDomain,
|
|
OUT LPWSTR *NewDNString);
|
|
|
|
DFSSTATUS
|
|
GetRegVolumesHKey(
|
|
IN LPWSTR MachineName,
|
|
OUT HKEY *VolumeKey);
|
|
|
|
DFSSTATUS
|
|
GetRegLocalVolumesHKey(
|
|
IN LPWSTR MachineName,
|
|
OUT HKEY *LocalVolumeKey);
|
|
|
|
//
|
|
// DfsRenameRegistries
|
|
//
|
|
// This contacts all root targets affected by the rename
|
|
// operation to possibly change their registry references
|
|
// to the obsolete domain name.
|
|
//
|
|
DFSSTATUS
|
|
DfsRenameRegistries(
|
|
IN DfsPathName *pPathName,
|
|
IN LPWSTR OldDomainName,
|
|
IN LPWSTR NewDomainName)
|
|
{
|
|
DFSSTATUS Status;
|
|
LPBYTE pBuffer = NULL;
|
|
DWORD ResumeHandle = 0;
|
|
DWORD EntriesRead = 0;
|
|
DWORD PrefMaxLen = 1;
|
|
DWORD Level = 4;
|
|
PDFS_INFO_4 pCurrentBuffer;
|
|
DWORD i;
|
|
PDFS_STORAGE_INFO pStorage;
|
|
|
|
//
|
|
// We are reading in just the ROOT.
|
|
// supw: DfsGetInfo is a better way to do this.
|
|
//
|
|
Status = DfsApiEnumerate( MODE_DIRECT,
|
|
pPathName->GetPathString(),
|
|
Level,
|
|
PrefMaxLen,
|
|
&pBuffer,
|
|
&EntriesRead,
|
|
&ResumeHandle);
|
|
|
|
if ((Status == ERROR_SUCCESS) && EntriesRead != 0)
|
|
{
|
|
pCurrentBuffer = (PDFS_INFO_4)pBuffer;
|
|
for( i = 0, pStorage = pCurrentBuffer->Storage;
|
|
i < pCurrentBuffer->NumberOfStorages;
|
|
i++, pStorage = pCurrentBuffer->Storage + i )
|
|
{
|
|
DebugInformation((L"DfsUtil: RenameRegistries: TARGET SERVER \\\\%ws\\%ws\n",
|
|
pStorage->ServerName, pStorage->ShareName));
|
|
|
|
//
|
|
// Now contact the appropriate server(s) for the root replicas
|
|
// and fix up their registry values if they happen to still
|
|
// point back at the obsolete domain name. Only the pre-Whistler
|
|
// servers do that currently.
|
|
// Errors are ignored entirely. The target server may or may not be a
|
|
// W2K machine.
|
|
//
|
|
// xxx supw: skip duplicate servernames here.
|
|
(VOID)DfsFixupRegistryValues(pStorage->ServerName,
|
|
pPathName->GetShareString(),
|
|
OldDomainName,
|
|
NewDomainName);
|
|
|
|
//
|
|
// Don't bother to resynchrnoize. W2K systems don't respond to RESYNCHRONIZE calls.
|
|
// Besides, the administrator is supposed to reboot all root servers.
|
|
//
|
|
// (VOID)SetInfoReSynchronize( pStorage->ServerName, pStorage->ShareName );
|
|
|
|
}
|
|
|
|
//
|
|
// Free the allocated memory.
|
|
//
|
|
DfsFreeApiBuffer(pBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsFixupRegistryValues(
|
|
IN LPWSTR MachineName,
|
|
IN LPWSTR RootName,
|
|
IN LPWSTR OldDomainName,
|
|
IN LPWSTR NewDomainName)
|
|
{
|
|
HKEY VolumeKey, LocalVolKey;
|
|
LPWSTR DNString = NULL;
|
|
LPWSTR EntryString = NULL;
|
|
DFSSTATUS Status;
|
|
DFSSTATUS RetStatus = ERROR_SUCCESS;
|
|
UNICODE_STRING OldDomUnicode;
|
|
UNICODE_STRING DomUnicode;
|
|
BOOLEAN Changed = FALSE;
|
|
|
|
Status = GetRegVolumesHKey( MachineName, &VolumeKey );
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
if (fSwDebug) {
|
|
DebugInformation((L"DfsUtil: RegOpen of DfsHost Volumes failed for machine %ws, with error 0x%x\n",
|
|
MachineName, Status));
|
|
}
|
|
|
|
//
|
|
// Only return fatal conditions that'll prompt us to abort.
|
|
//
|
|
return RetStatus;
|
|
}
|
|
|
|
RtlInitUnicodeString( &OldDomUnicode, OldDomainName );
|
|
|
|
//
|
|
// The \DfsHost\volumes\FTDfsObjectDN may need fixing.
|
|
//
|
|
Status = GetCurrentRegDomainName( VolumeKey,
|
|
UtilFtDfsConfigDNValueName,
|
|
&DNString);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
LPWSTR NewDNString;
|
|
|
|
//
|
|
// The DNString is of the form "CN=,CN=,...DC=DomainName,DC=..."
|
|
// See if the substring DC=DomainName matches the OldDomainName.
|
|
// If so substitute it with the NewDomainName and get a new DN string.
|
|
//
|
|
//if (DfsRenameFTConfigValueName( DNString, NewDomainName, &OldDomUnicode, &NewDNString ))
|
|
|
|
//
|
|
// Simply replace the existing string with a new DN string we generate.
|
|
// This assumes that the system has already rebooted since the DC was renamed.
|
|
//
|
|
{
|
|
Status = DfsGenerateDNPathString( RootName, &NewDNString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsSetRegDomainName( VolumeKey, UtilFtDfsConfigDNValueName, NewDNString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Changed = TRUE;
|
|
DebugInformation((L"FTDfsObjectDN = %ws\n", NewDNString));
|
|
}
|
|
DfsDeleteDNPathString( NewDNString );
|
|
}
|
|
}
|
|
|
|
delete [] DNString;
|
|
}
|
|
|
|
//
|
|
// The \DfsHost\volumes\LastDomainName shouldn't mention the old domain name.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetCurrentRegDomainName( VolumeKey,
|
|
DfsHostLastDomainValueName,
|
|
&DNString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
RtlInitUnicodeString( &DomUnicode, DNString );
|
|
if (RtlEqualDomainName( &DomUnicode, &OldDomUnicode ))
|
|
{
|
|
//
|
|
// Go ahead and make the substitution in the registry.
|
|
//
|
|
Status = DfsSetRegDomainName( VolumeKey,
|
|
DfsHostLastDomainValueName,
|
|
NewDomainName );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Changed = TRUE;
|
|
DebugInformation((L"DfsUtil: Rename of LastDomainName RegKey to %ws successful\n",
|
|
NewDomainName));
|
|
}
|
|
}
|
|
delete [] DNString;
|
|
}
|
|
}
|
|
|
|
RegCloseKey( VolumeKey );
|
|
|
|
|
|
Status = GetRegLocalVolumesHKey( MachineName, &LocalVolKey );
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
if (fSwDebug) {
|
|
DebugInformation((L"DfsUtil: RegOpen of Services\\DfsDriver\\LocalVolume failed for machine %ws, with error 0x%x\n",
|
|
MachineName, Status));
|
|
}
|
|
|
|
//
|
|
// Only return fatal conditions that'll prompt us to abort.
|
|
//
|
|
return RetStatus;
|
|
}
|
|
|
|
//
|
|
// The HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DfsDriver\LocalVolume
|
|
// shouldn't mention the old domain name.
|
|
//
|
|
|
|
Status = GetCurrentRegDomainName( LocalVolKey,
|
|
DfsDriverLocalVolumesEntryPath,
|
|
&EntryString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DfsPathName EntryPath;
|
|
Status = EntryPath.CreatePathName(EntryString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (RtlEqualDomainName( EntryPath.GetServerCountedString(), &OldDomUnicode ))
|
|
{
|
|
DfsPathName NewEntryPath;
|
|
//
|
|
// Go ahead and make the substitution in the registry.
|
|
// But first recreate the EntryPath using the new domain name.
|
|
//
|
|
NewEntryPath.SetPathName( NewDomainName,
|
|
EntryPath.GetShareString(),
|
|
1);
|
|
|
|
Status = DfsSetRegDomainName( LocalVolKey,
|
|
DfsDriverLocalVolumesEntryPath,
|
|
NewEntryPath.GetPathString() );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Changed = TRUE;
|
|
DebugInformation((L"DfsUtil: Rename of EntryPath RegKey from %ws to %ws successful\n",
|
|
EntryPath.GetPathString(), NewEntryPath.GetPathString()));
|
|
}
|
|
}
|
|
}
|
|
delete [] EntryString;
|
|
}
|
|
|
|
Status = GetCurrentRegDomainName( LocalVolKey,
|
|
DfsDriverLocalVolumesShortEntryPath,
|
|
&EntryString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DfsPathName ShortEntryPath;
|
|
Status = ShortEntryPath.CreatePathName(EntryString );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (RtlEqualDomainName( ShortEntryPath.GetServerCountedString(), &OldDomUnicode ))
|
|
{
|
|
//
|
|
// Go ahead and make the substitution in the registry.
|
|
// But first recreate the EntryPath using the new domain name.
|
|
//
|
|
DfsPathName NewEntryPath;
|
|
//
|
|
// Go ahead and make the substitution in the registry.
|
|
// But first recreate the EntryPath using the new domain name.
|
|
//
|
|
NewEntryPath.SetPathName( NewDomainName,
|
|
ShortEntryPath.GetShareString(),
|
|
1 );
|
|
|
|
Status = DfsSetRegDomainName( LocalVolKey,
|
|
DfsDriverLocalVolumesShortEntryPath,
|
|
NewEntryPath.GetPathString() );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Changed = TRUE;
|
|
DebugInformation((L"DfsUtil: Rename of ShortEntryPath RegKey From %ws to %ws successful\n",
|
|
ShortEntryPath.GetPathString(),
|
|
NewEntryPath.GetPathString()));
|
|
}
|
|
}
|
|
}
|
|
delete [] EntryString;
|
|
}
|
|
|
|
RegCloseKey( LocalVolKey );
|
|
|
|
if (Changed) {
|
|
DebugInformation((L"DfsUtil: Renamed registry references in root target system %wS\n", MachineName));
|
|
}
|
|
return RetStatus;
|
|
}
|
|
|
|
DFSSTATUS
|
|
GetCurrentRegDomainName(
|
|
IN HKEY VolumeKey,
|
|
IN LPWSTR DfsHostValueName,
|
|
OUT LPWSTR *pValueString)
|
|
{
|
|
LPWSTR FtDfsValue = NULL;
|
|
ULONG DataSize, DataType;
|
|
ULONG FtDfsValueSize;
|
|
|
|
DWORD Status;
|
|
|
|
*pValueString = NULL;
|
|
|
|
//
|
|
// If we opened the DFS hierarchy key properly, get the maximum
|
|
// size of any of the values under this key. This is so that we
|
|
// know how much memory to allocate, so that we can read any of
|
|
// the values we desire.
|
|
//
|
|
//
|
|
Status = RegQueryInfoKey( VolumeKey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
NULL, // # of subkeys
|
|
NULL, // max size of subkey name
|
|
NULL, // max size of class name
|
|
NULL, // # of values
|
|
NULL, // max size of value name
|
|
&DataSize, // max size of value data,
|
|
NULL, // security descriptor
|
|
NULL ); // Last write time
|
|
|
|
|
|
//
|
|
// check if the value is a string.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
FtDfsValueSize = DataSize;
|
|
FtDfsValue = (LPWSTR) new BYTE[DataSize];
|
|
if (FtDfsValue == NULL) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
//
|
|
// Now check if this is a Domain Based root.
|
|
//
|
|
Status = RegQueryValueEx( VolumeKey,
|
|
DfsHostValueName,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)FtDfsValue,
|
|
&FtDfsValueSize);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
*pValueString = FtDfsValue;
|
|
|
|
} else {
|
|
|
|
delete [] FtDfsValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsSetRegDomainName(
|
|
IN const HKEY DfsKey,
|
|
IN const LPWSTR RegValueName,
|
|
IN const LPWSTR DomainString)
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
Status = RegSetValueEx( DfsKey,
|
|
RegValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)DomainString,
|
|
wcslen(DomainString) * sizeof(WCHAR) );
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
GetRegVolumesHKey(
|
|
IN LPWSTR MachineName,
|
|
OUT HKEY *VolumeKey)
|
|
{
|
|
DFSSTATUS Status;
|
|
HKEY RootKey;
|
|
HKEY HostKey;
|
|
|
|
Status = RegConnectRegistry( MachineName,
|
|
HKEY_LOCAL_MACHINE,
|
|
&RootKey );
|
|
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Status = RegOpenKeyEx( RootKey,
|
|
UtilRegistryHostLocation,
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
&HostKey );
|
|
|
|
if (RootKey != HKEY_LOCAL_MACHINE)
|
|
{
|
|
RegCloseKey( RootKey );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = RegOpenKeyEx( HostKey,
|
|
UtilVolumesLocation,
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
VolumeKey );
|
|
|
|
RegCloseKey( HostKey );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
GetRegLocalVolumesHKey(
|
|
IN LPWSTR MachineName,
|
|
OUT HKEY *LocalVolumeKey)
|
|
{
|
|
DFSSTATUS Status;
|
|
HKEY RootKey;
|
|
HKEY LocalParentKey;
|
|
|
|
Status = RegConnectRegistry( MachineName,
|
|
HKEY_LOCAL_MACHINE,
|
|
&RootKey );
|
|
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Status = RegOpenKeyEx( RootKey,
|
|
DfsDriverLocalVolumesLocation,
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
&LocalParentKey );
|
|
|
|
if (RootKey != HKEY_LOCAL_MACHINE)
|
|
{
|
|
RegCloseKey( RootKey );
|
|
}
|
|
|
|
//
|
|
// We know for a fact that the old W2K servers can
|
|
// host only one root. Therefore, there can only be one
|
|
// child here.
|
|
//
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
DWORD ChildNameLen = MAX_PATH;
|
|
WCHAR ChildName[MAX_PATH];
|
|
|
|
Status = RegEnumKeyEx( LocalParentKey,
|
|
0,
|
|
ChildName,
|
|
&ChildNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// We have the name of a child, so open the key to
|
|
// that root.
|
|
//
|
|
Status = RegOpenKeyEx( LocalParentKey,
|
|
ChildName,
|
|
0,
|
|
KEY_READ|KEY_WRITE,
|
|
LocalVolumeKey );
|
|
}
|
|
|
|
RegCloseKey( LocalParentKey );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsRenameLinksToDomain(
|
|
IN DfsPathName *pDfsPath,
|
|
IN LPWSTR OldDomainName,
|
|
IN LPWSTR NewDomainName)
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
DebugInformation((L"DfsUtil: Starting renaming links from %ws to %ws in ROOT %ws\n",
|
|
OldDomainName, NewDomainName, pDfsPath->GetPathString()));
|
|
|
|
Status = DfsRenameLinks( pDfsPath->GetPathString(), OldDomainName, NewDomainName );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
(VOID)DfsRenameRegistries( pDfsPath, OldDomainName, NewDomainName );
|
|
CommandSucceeded = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|