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.
 
 
 
 
 
 

549 lines
15 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: dfsCompCheck.c
//
// Contents: Checks if the existing DFS root is compatible with Windows XP server.
//
// History: Aug. 8 2001, Author: navjotv, some code picked up from other dfs source code files.
//
//
//-----------------------------------------------------------------------------
#include "dfsCompCheck.hxx"
BOOLEAN
IsNTFS(
PFILE_FS_ATTRIBUTE_INFORMATION pInfo);
LPWSTR DfsOldStandaloneChild = L"domainroot";
LPWSTR DfsOldRegistryLocation = L"SOFTWARE\\Microsoft\\DfsHost\\volumes";
LPWSTR DfsLogicalShareValueName = L"LogicalShare";
LPWSTR DfsRootShareValueName = L"RootShare";
//+-------------------------------------------------------------------------
//
// Function: CompatibilityCheck
//
// Arguments: CompatibilityCallback - function to call if a compatibility problem is found
// Context
//
// Returns: TRUE on success
// FALSE otherwise
//
//
// Description: Check if existing DFS root will be supported after system upgarde.
//
//--------------------------------------------------------------------------
BOOLEAN
APIENTRY
CompatibilityCheck(PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context)
{
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus = STATUS_SUCCESS;
HKEY OldStandaloneDfsKey;
BOOLEAN MachineContacted = FALSE;
ULONG pAttribInfoSize;
PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING DirectoryName;
HANDLE DirHandle = NULL;
UNICODE_STRING PhysicalShare;
BOOLEAN ReturnVal = FALSE;
COMPATIBILITY_ENTRY CompEntry;
CompEntry.Description = L"The current DFS root hosted on this server will not be supported after this system upgrade";
CompEntry.HtmlName = L"compdata\\dfsComp.htm";
CompEntry.TextName = L"compdata\\dfsComp.txt";
CompEntry.RegKeyName = NULL;
CompEntry.RegValName = NULL;
CompEntry.RegValDataSize = NULL;
CompEntry.RegValData = NULL;
CompEntry.SaveValue = NULL;
CompEntry.Flags = 0x00000000;
CompEntry.InfName = NULL;
CompEntry.InfSection = NULL;
printf("\n dfsCompCheck:: Entering CompatibilityCheck");
Status = GetOldDfsRegistryKey( L"",
FALSE,
&MachineContacted,
&OldStandaloneDfsKey );
// If we cn open this registry key, then we know that this machine
//has old style DFS.
if (Status == ERROR_SUCCESS)
{
Status = GetRootPhysicalShare(OldStandaloneDfsKey,
&PhysicalShare);
if (Status == ERROR_SUCCESS)
{
Status = DfsGetSharePath(L"",
PhysicalShare.Buffer,
&DirectoryName);
if ( (DirectoryName.Buffer == NULL) ||
(DirectoryName.Length == 0) )
{
Status = ERROR_INVALID_PARAMETER;
}
ReleaseRootPhysicalShare(&PhysicalShare);
if (Status == ERROR_SUCCESS)
{
//why MAX_PATH??
pAttribInfoSize = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH;
pAttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION) new BYTE [pAttribInfoSize];
if (pAttribInfo != NULL)
{
InitializeObjectAttributes ( &ObjectAttributes,
&DirectoryName,
OBJ_CASE_INSENSITIVE, //Attributes
NULL, //Root handle
NULL ); //Security descriptor.
NtStatus = NtOpenFile( &DirHandle,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT );
if (NtStatus == STATUS_SUCCESS)
{
//
// Query for the basic information, which has the attributes.
//
NtStatus = NtQueryVolumeInformationFile( DirHandle,
&IoStatusBlock,
pAttribInfo,
pAttribInfoSize,
FileFsAttributeInformation );
if (NtStatus == STATUS_SUCCESS)
{
//
// If the attributes indicate reparse point, we have a reparse
// point directory on our hands.
//
if ( (pAttribInfo->FileSystemAttributes & FILE_SUPPORTS_REPARSE_POINTS) == 0
&& !IsNTFS(pAttribInfo))
{
NtStatus = STATUS_NOT_SUPPORTED;
CompatibilityCallback(&CompEntry, Context);
ReturnVal = FALSE;
}
else
{
ReturnVal = TRUE;
}
}
CloseHandle (DirHandle);
delete [] pAttribInfo;
}
}
}
}
}
else
{
//Does not have old DFS
ReturnVal = TRUE;
}
return ReturnVal;
}
//+-------------------------------------------------------------------------
//
// Function: GetOldStandaloneRegistryKey
//
// Arguments:
//
// Returns: SUCCESS or error
//
// Description: Checks if Old Standalone DFS registry key exists.
//
//
//--------------------------------------------------------------------------
static
DFSSTATUS
GetOldStandaloneRegistryKey( IN LPWSTR MachineName,
BOOLEAN WritePermission,
OUT BOOLEAN *pMachineContacted,
OUT PHKEY pDfsRegKey )
{
DFSSTATUS Status;
HKEY DfsKey;
Status = GetOldDfsRegistryKey (MachineName,
WritePermission,
pMachineContacted,
&DfsKey );
if (Status == ERROR_SUCCESS)
{
Status = RegOpenKeyEx( DfsKey,
DfsOldStandaloneChild,
0,
KEY_READ | (WritePermission ? KEY_WRITE : 0),
pDfsRegKey );
RegCloseKey( DfsKey);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: GetOldDfsRegistryKey
//
// Arguments:
//
// Returns: SUCCESS or error
//
// Description: Checks if Old DFS registry key exists.
//
//
//--------------------------------------------------------------------------
static
DFSSTATUS
GetOldDfsRegistryKey( IN LPWSTR MachineName,
BOOLEAN WritePermission,
OUT BOOLEAN *pMachineContacted,
OUT PHKEY pDfsRegKey )
{
return GetDfsRegistryKey (MachineName,
DfsOldRegistryLocation,
WritePermission,
pMachineContacted,
pDfsRegKey );
}
//+-------------------------------------------------------------------------
//
// Function: GetDfsRegistryKey
//
// Arguments:
//
// Returns: SUCCESS or error
//
// Description:
// Function GetDfsRegistryKey: This function takes a Name as the input,
// and looks up all DFS roots in that namespace.
//
//--------------------------------------------------------------------------
static
DFSSTATUS
GetDfsRegistryKey( IN LPWSTR MachineName,
IN LPWSTR LocationString,
BOOLEAN WritePermission,
OUT BOOLEAN *pMachineContacted,
OUT PHKEY pDfsRegKey )
{
DFSSTATUS Status;
HKEY RootKey;
BOOLEAN Contacted = FALSE;
LPWSTR UseMachineName = NULL;
REGSAM DesiredAccess = KEY_READ;
if (WritePermission == TRUE)
{
DesiredAccess |= KEY_WRITE;
}
if (IsEmptyString(MachineName) == FALSE) {
UseMachineName = MachineName;
}
Status = RegConnectRegistry( UseMachineName,
HKEY_LOCAL_MACHINE,
&RootKey );
if ( Status == ERROR_SUCCESS )
{
Contacted = TRUE;
Status = RegOpenKeyEx( RootKey,
LocationString,
0,
DesiredAccess,
pDfsRegKey );
//
// There appears to be a bug in the registry code. When
// we connect to the local machine, the key that is returned
// in the RegConnectRegistry is HKEY_LOCAL_MACHINE. If we
// then attempt to close it here, it affects other threads
// that are using this code: they get STATUS_INVALID_HANDLE
// in some cases. So, dont close the key if it is
// HKEY_LOCAL_MACHINE.
//
if (RootKey != HKEY_LOCAL_MACHINE)
{
RegCloseKey( RootKey );
}
}
if (pMachineContacted != NULL)
{
*pMachineContacted = Contacted;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: GetRootPhysicalShare
//
// Arguments:
//
// Returns: SUCCESS or error
//
// Description: Gets the value of the DFS root share
//
//
//--------------------------------------------------------------------------
DFSSTATUS
GetRootPhysicalShare(
HKEY RootKey,
PUNICODE_STRING pRootPhysicalShare )
{
DFSSTATUS Status;
ULONG DataSize, DataType;
LPWSTR DfsRootShare = NULL;
Status = RegQueryInfoKey( RootKey, // 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
if (Status == ERROR_SUCCESS)
{
DfsRootShare = (LPWSTR) new BYTE [DataSize];
if ( DfsRootShare == NULL )
{
Status = ERROR_NOT_ENOUGH_MEMORY;
} else
{
Status = RegQueryValueEx( RootKey,
DfsRootShareValueName,
NULL,
&DataType,
(LPBYTE)DfsRootShare,
&DataSize );
}
}
if (Status == ERROR_SUCCESS)
{
if (DataType == REG_SZ)
{
RtlInitUnicodeString( pRootPhysicalShare, DfsRootShare );
}
else {
Status = STATUS_INVALID_PARAMETER;
}
}
if (Status != ERROR_SUCCESS)
{
if (DfsRootShare != NULL)
{
delete [] DfsRootShare;
}
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: ReleaseRootPhysicalShare
//
// Arguments:
//
// Returns:
//
// Description: Releases memory for pRootPhysicalShare->Buffer.
//
//
//--------------------------------------------------------------------------
VOID
ReleaseRootPhysicalShare(
PUNICODE_STRING pRootPhysicalShare )
{
delete [] pRootPhysicalShare->Buffer;
}
//+-------------------------------------------------------------------------
//
// Function: DfsGetSharePath
//
// Arguments: ServerName - the name of the server
// ShareName - the name of the share
// pPathName - the unicode string representing the NT name
// of the local path representing the share
//
// Returns: SUCCESS or error
//
// Description: This routine takes a servername and a sharename, and
// returns an NT pathname to the physical resource that is
// backing the share name.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetSharePath(
IN LPWSTR ServerName,
IN LPWSTR ShareName,
OUT PUNICODE_STRING pPathName )
{
LPWSTR UseServerName = NULL;
ULONG InfoLevel = 2;
PSHARE_INFO_2 pShareInfo;
NET_API_STATUS NetStatus;
DFSSTATUS Status;
UNICODE_STRING NtSharePath;
if (IsEmptyString(ServerName) == FALSE)
{
UseServerName = ServerName;
}
NetStatus = NetShareGetInfo( UseServerName,
ShareName,
InfoLevel,
(LPBYTE *)&pShareInfo );
if (NetStatus != ERROR_SUCCESS)
{
Status = (DFSSTATUS)NetStatus;
return Status;
}
if( RtlDosPathNameToNtPathName_U(pShareInfo->shi2_path,
&NtSharePath,
NULL,
NULL ) == TRUE )
{
Status = DfsCreateUnicodeString( pPathName,
&NtSharePath );
RtlFreeUnicodeString( &NtSharePath );
}
else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
NetApiBufferFree( pShareInfo );
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsCreateUnicodeString
//
// Arguments: pDest - the destination unicode string
// pSrc - the source unicode string
//
// Returns: SUCCESS or error
//
// Description: This routine creates a new unicode string that is a copy
// of the original. The copied unicode string has a buffer
// that is null terminated, so the buffer can be used as a
// normal string if necessary.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsCreateUnicodeString(
PUNICODE_STRING pDest,
PUNICODE_STRING pSrc )
{
LPWSTR NewString;
NewString = (LPWSTR) malloc(pSrc->Length + sizeof(WCHAR));
if ( NewString == NULL )
{
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlCopyMemory( NewString, pSrc->Buffer, pSrc->Length);
NewString[ pSrc->Length / sizeof(WCHAR)] = UNICODE_NULL;
RtlInitUnicodeString( pDest, NewString );
return ERROR_SUCCESS;
}
//+-------------------------------------------------------------------------
//
// Function: IsNTFS
//
// Arguments: pInfo
//
// Returns: True - if NTFS
// False - if not NTFS
//
// Description: Checks if filesystem is NTFS
//
//--------------------------------------------------------------------------
BOOLEAN
IsNTFS(
PFILE_FS_ATTRIBUTE_INFORMATION pInfo)
{
if (pInfo->FileSystemNameLength == 8 &&
pInfo->FileSystemName[0] == 'N' &&
pInfo->FileSystemName[1] == 'T' &&
pInfo->FileSystemName[2] == 'F' &&
pInfo->FileSystemName[3] == 'S')
return TRUE;
else
return FALSE;
}