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.
 
 
 
 
 
 

1131 lines
31 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsDownLevel.cxx
//
// Contents: Contains APIs to communicate old DFS Servers
//
// Classes: none.
//
// History: Jan. 24 2001, Author: Rohanp
//
//-----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <windef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <lm.h>
#include <winsock2.h>
#include <smbtypes.h>
#pragma warning(disable: 4200) //nonstandard extension used: zero-sized array in struct/union (line 1085
#include <smbtrans.h>
#pragma warning(default: 4200)
#include <dsgetdc.h>
#include <dsrole.h>
#include <DfsReferralData.h>
#include <DfsReferral.hxx>
#include <dfsheader.h>
#include <Dfsumr.h>
#include <dfsfilterapi.hxx>
#define PATH_DELIMITER L'\\'
//+-------------------------------------------------------------------------
//
// Function: DfspGetV1ReferralSize
//
// Arguments: List of referrals
//
// Returns: size of referrals
//
//
// Description: calculates size needed to fit V1 referrals
//
//--------------------------------------------------------------------------
ULONG
DfspGetV1ReferralSize(
IN PREFERRAL_HEADER pRefHeader)
{
ULONG i = 0;
ULONG size = 0;
PREPLICA_INFORMATION pRep = NULL;
size = sizeof( RESP_GET_DFS_REFERRAL );
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRefHeader->ReplicaCount; i++)
{
size += sizeof(DFS_REFERRAL_V1) +
pRep->ReplicaNameLength +
sizeof(UNICODE_NULL);
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
return( size );
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV2ReferralSize
//
// Arguments: List of referrals
//
// Returns: size of referrals
//
//
// Description: calculates size needed to fit V2 referrals
//
//--------------------------------------------------------------------------
ULONG
DfspGetV2ReferralSize(
IN PREFERRAL_HEADER pRefHeader)
{
ULONG i = 0;
ULONG size = 0;
PREPLICA_INFORMATION pRep = NULL;
UNICODE_STRING PrefixTail;
size = sizeof( RESP_GET_DFS_REFERRAL );
PrefixTail.Length = 0;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRefHeader->ReplicaCount; i++)
{
size += sizeof(DFS_REFERRAL_V2) +
pRep->ReplicaNameLength +
sizeof(UNICODE_NULL);
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
size += sizeof(UNICODE_PATH_SEP) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_NULL);
size += sizeof(UNICODE_PATH_SEP) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_NULL);
return( size );
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV3ReferralSize
//
// Arguments: List of referrals
//
// Returns: size of referrals
//
//
// Description: calculates size needed to fit V3 referrals
//
//--------------------------------------------------------------------------
ULONG
DfspGetV3ReferralSize(
IN PREFERRAL_HEADER pRefHeader)
{
ULONG i = 0;
ULONG size = 0;
PREPLICA_INFORMATION pRep = NULL;
UNICODE_STRING PrefixTail;
size = sizeof( RESP_GET_DFS_REFERRAL );
PrefixTail.Length = 0;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRefHeader->ReplicaCount; i++)
{
size += sizeof(DFS_REFERRAL_V3) +
pRep->ReplicaNameLength +
sizeof(UNICODE_NULL);
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
size += sizeof(UNICODE_PATH_SEP) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_NULL);
size += sizeof(UNICODE_PATH_SEP) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_NULL);
return( size );
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV1Referral
//
// Arguments: List of referrals
//
// Returns:
//
//
// Description: Copies the V1 referrals to output buffer
//
//--------------------------------------------------------------------------
VOID
DfspGetV1Referral(
IN PREFERRAL_HEADER pRefHeader,
OUT PRESP_GET_DFS_REFERRAL Ref)
{
PDFS_REFERRAL_V1 pv1 = NULL;
PREPLICA_INFORMATION pRep = NULL;
ULONG i = 0;
Ref->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
Ref->ReferralServers = 1;
Ref->StorageServers = 1;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
pv1 = &Ref->Referrals[0].v1;
for (i = 0; i < pRefHeader->ReplicaCount; i++)
{
pv1->VersionNumber = 1;
pv1->Size = (USHORT)( sizeof(DFS_REFERRAL_V1) +
pRep->ReplicaNameLength +
sizeof(UNICODE_NULL));
if (((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL) == 0) &&
((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN) == 0))
{
pv1->ServerType = 0;
}
else
{
pv1->ServerType = 1;
}
RtlCopyMemory(
pv1->ShareName,
pRep->ReplicaName,
pRep->ReplicaNameLength);
pv1->ShareName[ pRep->ReplicaNameLength / sizeof(WCHAR) ] =
UNICODE_NULL;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
pv1 = (PDFS_REFERRAL_V1) ( ((PCHAR) pv1) + pv1->Size );
}
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV2Referral
//
// Arguments: List of referrals
//
// Returns:
//
//
// Description: Copies the V2 referrals to output buffer
//
//--------------------------------------------------------------------------
NTSTATUS
DfspGetV2Referral(
IN PREFERRAL_HEADER pRefHeader,
IN ULONG BufferSize,
OUT PRESP_GET_DFS_REFERRAL pRef,
OUT PULONG ReferralSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
PDFS_REFERRAL_V2 pv2 = NULL;
PREPLICA_INFORMATION pRep = NULL;
ULONG i = 0;
ULONG CumulativeSize = 0;
ULONG CurrentSize = 0;
LPWSTR pDfsPath = NULL;
LPWSTR pAlternatePath = NULL;
LPWSTR pNextAddress = NULL;
LPWSTR LinkName;
ULONG LinkNameLength;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
// Calculate the size of the referral, and make sure our size does not
// exceed the passed in buffer len.
CumulativeSize =
sizeof (RESP_GET_DFS_REFERRAL) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
if (BufferSize < CumulativeSize)
{
Status = ERROR_MORE_DATA;
return Status;
}
if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN)
{
pRef->ReferralServers = 1;
pRef->StorageServers = 0;
}
else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
{
pRef->ReferralServers = 1;
pRef->StorageServers = 1;
}
else
{
pRef->ReferralServers = 0;
pRef->StorageServers = 1;
}
pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
pv2 = &pRef->Referrals[0].v2;
//see how many referrals we can actually fit into the buffer
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
CurrentSize = sizeof(DFS_REFERRAL_V3) +
pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
if ((CumulativeSize + CurrentSize) >= BufferSize)
break;
CumulativeSize += CurrentSize;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
// Adjust the number of referrals accordingly.
pRef->NumberOfReferrals = (USHORT)i;
//
// we have more than one service, but cannot fit any into the buffer
// return buffer overflow.
//
if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
{
return ERROR_MORE_DATA;
}
//
// Copy the volume prefix into the response buffer, just past the end
// of all the V3 referrals
//
pNextAddress = pDfsPath = (LPWSTR) &pv2[ pRef->NumberOfReferrals ];
LinkName = pRefHeader->LinkName;
LinkNameLength = pRefHeader->LinkNameLength;
while ((LinkNameLength > (sizeof(WCHAR) + sizeof(WCHAR))) &&
(LinkName[0] == UNICODE_PATH_SEP) &&
(LinkName[1] == UNICODE_PATH_SEP))
{
LinkName++;
LinkNameLength -= sizeof(WCHAR);
}
pRef->PathConsumed = (USHORT)LinkNameLength;
RtlCopyMemory(
pNextAddress,
LinkName,
LinkNameLength);
pNextAddress += LinkNameLength/sizeof(WCHAR);
*pNextAddress++ = UNICODE_NULL;
//
// Copy the 8.3 volume prefix into the response buffer after the
// dfsPath
//
pAlternatePath = pNextAddress;
RtlCopyMemory(
pNextAddress,
LinkName,
LinkNameLength);
pNextAddress += LinkNameLength/sizeof(WCHAR);
*pNextAddress++ = UNICODE_NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
pv2->VersionNumber = 2;
pv2->Size = sizeof(DFS_REFERRAL_V2);
//
// Clients who use V2 Referrals (< NT4SP5 for example) expect ServerType of 0
// for SMB link targets. Root referrals and targets pointing at other
// DFS namespaces need to send ServerType of 1.
//
if (((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL) == 0) &&
((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN) == 0))
{
pv2->ServerType = 0;
}
else
{
pv2->ServerType = 1;
}
pv2->Proximity = 0;
pv2->TimeToLive = pRefHeader->Timeout;
pv2->DfsPathOffset = (USHORT) (((PCHAR) pDfsPath) - ((PCHAR) pv2));
pv2->DfsAlternatePathOffset =
(USHORT) (((PCHAR) pAlternatePath) - ((PCHAR) pv2));
pv2->NetworkAddressOffset =
(USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv2));
RtlCopyMemory(
pNextAddress,
pRep->ReplicaName,
pRep->ReplicaNameLength);
pNextAddress[ pRep->ReplicaNameLength/sizeof(WCHAR) ] = UNICODE_NULL;
pNextAddress += pRep->ReplicaNameLength/sizeof(WCHAR) + 1;
pv2++;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
*ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV3DomainReferral
//
// Arguments: dfsdev: fill this in.
//
// Returns:
//
//
// Description: Copies the V3 referrals to output buffer
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetV3DomainReferral(
IN PREFERRAL_HEADER pRefHeader,
IN ULONG BufferSize,
OUT PRESP_GET_DFS_REFERRAL pRef,
OUT PULONG ReferralSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
PDFS_REFERRAL_V3 pv3 = NULL;
PREPLICA_INFORMATION pRep = NULL;
ULONG i = 0;
ULONG CumulativeSize = 0;
ULONG CurrentSize = 0;
LPWSTR pDfsPath = NULL;
LPWSTR pAlternatePath = NULL;
LPWSTR pNextAddress = NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
// Calculate the size of the referral, and make sure our size does not
// exceed the passed in buffer len.
CumulativeSize = sizeof (RESP_GET_DFS_REFERRAL);
if (BufferSize < CumulativeSize)
{
Status = ERROR_MORE_DATA;
return Status;
}
//
// For compatibility, set all referrals to be storage servers.
// and only the root referral as the referral servers.
// This appears to keep the client happy for all cases
// dfsdev: investigate if this is fine.
//
pRef->StorageServers = 0;
pRef->ReferralServers = 0;
pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
pRef->PathConsumed = 0;
pv3 = &pRef->Referrals[0].v3;
//
// double unicode_null at end.
//
CumulativeSize += sizeof(UNICODE_NULL);
//see how many referrals we can actually fit into the buffer
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
CurrentSize = sizeof(DFS_REFERRAL_V3) + sizeof(UNICODE_PATH_SEP) +
pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
if ((CumulativeSize + CurrentSize) >= BufferSize)
{
Status = ERROR_MORE_DATA;
break;
}
CumulativeSize += CurrentSize;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
if (Status == ERROR_MORE_DATA)
{
#define EVENT_POSTED 1
#define EVENT_NOT_POSTED 0
static LONG DomainOverflowMaxEventPosted = 0;
static LONG DomainOverflowMinEventPosted = 0;
LONG PostedState;
PostedState = InterlockedCompareExchange(&DomainOverflowMinEventPosted,
EVENT_POSTED, EVENT_NOT_POSTED);
if (PostedState == EVENT_NOT_POSTED)
{
DfsLogDfsEvent(DFS_INFO_DOMAIN_REFERRAL_MIN_OVERFLOW,
0, NULL, 0);
}
if (BufferSize < MAX_REFERRAL_SIZE)
{
return Status;
}
else
{
Status = ERROR_SUCCESS;
PostedState = InterlockedCompareExchange(&DomainOverflowMaxEventPosted,
EVENT_POSTED, EVENT_NOT_POSTED);
if (PostedState == EVENT_NOT_POSTED)
{
//post event;
DfsLogDfsEvent(DFS_WARN_DOMAIN_REFERRAL_OVERFLOW,
0, NULL, 0);
}
}
}
// Adjust the number of referrals accordingly.
pRef->NumberOfReferrals = (USHORT)i;
//
// we have more than one service, but cannot fit any into the buffer
// return buffer overflow.
//
if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
{
return ERROR_MORE_DATA;
}
//
// Copy the volume prefix into the response buffer, just past the end
// of all the V3 referrals
//
pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
pv3->VersionNumber = 3;
pv3->Size = sizeof(DFS_REFERRAL_V3);
pv3->ServerType = 0;
pv3->StripPath = 0; // for now
pv3->NameListReferral = 1;
pv3->TimeToLive = 600;
pv3->SpecialNameOffset =
(USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
pv3->NumberOfExpandedNames = 0;
pv3->ExpandedNameOffset = 0;
//
// dfsdev investigate.
//
*pNextAddress++ = UNICODE_PATH_SEP;
RtlMoveMemory(
pNextAddress,
pRep->ReplicaName,
pRep->ReplicaNameLength);
pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
pv3++;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
*ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV3Referral
//
// Arguments: List of referrals
//
// Returns:
//
//
// Description: Copies the V3 referrals to output buffer
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetV3DCReferral(
IN PREFERRAL_HEADER pRefHeader,
IN ULONG BufferSize,
OUT PRESP_GET_DFS_REFERRAL pRef,
OUT PULONG ReferralSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
PDFS_REFERRAL_V3 pv3 = NULL;
PREPLICA_INFORMATION pRep = NULL;
ULONG i = 0;
ULONG CumulativeSize = 0;
ULONG CurrentSize = 0;
LPWSTR pDfsPath = NULL;
LPWSTR pAlternatePath = NULL;
LPWSTR pNextAddress = NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
// Calculate the size of the referral, and make sure our size does not
// exceed the passed in buffer len.
CumulativeSize = sizeof (RESP_GET_DFS_REFERRAL) +
pRefHeader->LinkNameLength + sizeof(UNICODE_NULL);
if (BufferSize < CumulativeSize)
{
Status = ERROR_MORE_DATA;
return Status;
}
//
// For compatibility, set all referrals to be storage servers.
// and only the root referral as the referral servers.
// This appears to keep the client happy for all cases
// dfsdev: investigate if this is fine.
//
pRef->StorageServers = 0;
pRef->ReferralServers = 0;
pRef->NumberOfReferrals = 1;
pRef->PathConsumed = 0;
pv3 = &pRef->Referrals[0].v3;
//
// double unicode_null at end.
//
CumulativeSize += sizeof(UNICODE_NULL);
//see how many referrals we can actually fit into the buffer
for (i = 0; i < pRefHeader->ReplicaCount; i++)
{
CurrentSize = sizeof(UNICODE_PATH_SEP) +
pRep->ReplicaNameLength +
sizeof(UNICODE_NULL);
if ((CumulativeSize + CurrentSize) >= BufferSize)
break;
CumulativeSize += CurrentSize;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
// Adjust the number of referrals accordingly.
pv3->NumberOfExpandedNames = (USHORT)i;
//
// we have more than one service, but cannot fit any into the buffer
// return buffer overflow.
//
if ((pRefHeader->ReplicaCount > 0) && (pv3->NumberOfExpandedNames == 0))
{
return ERROR_MORE_DATA;
}
//
// Copy the volume prefix into the response buffer, just past the end
// of all the V3 referrals
//
pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
pv3->SpecialNameOffset =
(USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
*pNextAddress++ = UNICODE_PATH_SEP;
RtlMoveMemory(
pNextAddress,
pRefHeader->LinkName,
pRefHeader->LinkNameLength);
pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
*pNextAddress++ = UNICODE_NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
pv3->VersionNumber = 3;
pv3->Size = sizeof(DFS_REFERRAL_V3);
pv3->ServerType = 0;
pv3->StripPath = 0; // for now
pv3->NameListReferral = 1;
pv3->TimeToLive = 600;
pv3->ExpandedNameOffset =
(USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
for (i = 0; i < pv3->NumberOfExpandedNames; i++) {
//
// dfsdev: this is very confusing..
// investigate. Each of the referrals we call keep
// adding a unicode path sep.
//
#if 0
*pNextAddress++ = UNICODE_PATH_SEP;
#endif
RtlCopyMemory(
pNextAddress,
pRep->ReplicaName,
pRep->ReplicaNameLength );
pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
*ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
return Status;
}
DFSSTATUS
DfsGetV3NormalReferral(
IN PREFERRAL_HEADER pRefHeader,
IN ULONG BufferSize,
OUT PRESP_GET_DFS_REFERRAL pRef,
OUT PULONG ReferralSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
PDFS_REFERRAL_V3 pv3 = NULL;
PREPLICA_INFORMATION pRep = NULL;
ULONG i = 0;
ULONG CumulativeSize = 0;
ULONG CurrentSize = 0;
LPWSTR pDfsPath = NULL;
LPWSTR pAlternatePath = NULL;
LPWSTR pNextAddress = NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
// Calculate the size of the referral, and make sure our size does not
// exceed the passed in buffer len.
CumulativeSize =
sizeof (RESP_GET_DFS_REFERRAL) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
pRefHeader->LinkNameLength +
sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
if (BufferSize < CumulativeSize)
{
Status = ERROR_MORE_DATA;
return Status;
}
//
// For compatibility, set all referrals to be storage servers.
// and only the root referral as the referral servers.
// This appears to keep the client happy for all cases
// dfsdev: investigate if this is fine.
//
if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN)
{
pRef->ReferralServers = 1;
pRef->StorageServers = 0;
}
else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
{
pRef->ReferralServers = 1;
pRef->StorageServers = 1;
}
else
{
pRef->ReferralServers = 0;
pRef->StorageServers = 1;
}
pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
pv3 = &pRef->Referrals[0].v3;
//see how many referrals we can actually fit into the buffer
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
CurrentSize = sizeof(DFS_REFERRAL_V3) +
pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
if ((CumulativeSize + CurrentSize) >= BufferSize)
break;
CumulativeSize += CurrentSize;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
// Adjust the number of referrals accordingly.
pRef->NumberOfReferrals = (USHORT)i;
//
// we have more than one service, but cannot fit any into the buffer
// return buffer overflow.
//
if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
{
return ERROR_MORE_DATA;
}
//
// Copy the volume prefix into the response buffer, just past the end
// of all the V3 referrals
//
pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
RtlMoveMemory(
pNextAddress,
pRefHeader->LinkName,
pRefHeader->LinkNameLength);
pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
*pNextAddress++ = UNICODE_NULL;
//
// Copy the 8.3 volume prefix into the response buffer after the
// dfsPath
//
pAlternatePath = pNextAddress;
RtlMoveMemory(
pNextAddress,
pRefHeader->LinkName,
pRefHeader->LinkNameLength);
pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
*pNextAddress++ = UNICODE_NULL;
pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
for (i = 0; i < pRef->NumberOfReferrals; i++)
{
pv3->VersionNumber = 3;
pv3->Size = sizeof(DFS_REFERRAL_V3);
//
// The server type is important for the client. Set to 1 for
// root referral, and 0 otherwise. It appears to keep the client
// happy.
// dfsdev: investigate further.
//
if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
{
pv3->ServerType = 1;
}
else {
pv3->ServerType = 0;
}
pv3->StripPath = 0; // for now
pv3->NameListReferral = 0;
pv3->TimeToLive = pRefHeader->Timeout;
pv3->DfsPathOffset = (USHORT) (((PCHAR) pDfsPath) - ((PCHAR) pv3));
pv3->DfsAlternatePathOffset =
(USHORT) (((PCHAR) pAlternatePath) - ((PCHAR) pv3));
pv3->NetworkAddressOffset =
(USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
RtlZeroMemory(
&pv3->ServiceSiteGuid,
sizeof (GUID));
RtlMoveMemory(
pNextAddress,
pRep->ReplicaName,
pRep->ReplicaNameLength);
pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
pv3++;
pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
}
*ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetV3Referral
//
// Arguments: List of referrals
//
// Returns:
//
//
// Description: Copies the V3 referrals to output buffer
//
//--------------------------------------------------------------------------
NTSTATUS
DfspGetV3Referral(
IN PREFERRAL_HEADER pRefHeader,
IN ULONG BufferSize,
OUT PRESP_GET_DFS_REFERRAL pRef,
OUT PULONG ReferralSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
//
//The client could be asking for either the trusted domains referral
// or for the list of DC for a domain or for a normal dfs referral
// to a path.
//
if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_DOMAIN_REFERRAL)
{
Status = DfsGetV3DomainReferral( pRefHeader,
BufferSize,
pRef,
ReferralSize );
}
else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_DOMAIN_DC_REFERRAL)
{
Status = DfsGetV3DCReferral( pRefHeader,
BufferSize,
pRef,
ReferralSize );
}
else
{
Status = DfsGetV3NormalReferral( pRefHeader,
BufferSize,
pRef,
ReferralSize );
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: ProcessOldDfsServerRequest
//
// Arguments:
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: Converts new data to what the old DFS server expects
//
//--------------------------------------------------------------------------
DFSSTATUS ProcessOldDfsServerRequest(HANDLE hDriverHandle,
PUMRX_USERMODE_WORKITEM ProtocolBuffer,
PUMR_GETDFSREPLICAS_REQ pGetReplicaRequest,
REFERRAL_HEADER *pReferral,
ULONG *ReturnedDataSize)
{
DFSSTATUS Status = ERROR_SUCCESS;
ULONG Size = 0;
ULONG SendSize = 0;
ULONG MaxLevel = 0;
DWORD BytesReturned = 0;
PRESP_GET_DFS_REFERRAL pRef = NULL;
PBYTE pSendBuffer = NULL;
PUMRX_USERMODE_WORKITEM pSendWorkItem = NULL;
//get the level
MaxLevel = pGetReplicaRequest->RepInfo.MaxReferralLevel;
//check if MaxLevel is legal
switch (MaxLevel)
{
case 1:
Size = DfspGetV1ReferralSize(pReferral);
break;
case 2:
Size = DfspGetV2ReferralSize(pReferral);
break;
case 3:
Size = DfspGetV3ReferralSize(pReferral);
break;
default:
ASSERT(FALSE && "Invalid MaxLevel");
Status = ERROR_INVALID_PARAMETER;
break;
}
if(Status != ERROR_SUCCESS)
{
return Status;
}
SendSize = UMR_ALIGN(pGetReplicaRequest->RepInfo.ClientBufferSize) + sizeof(UMRX_USERMODE_WORKITEM);
pSendWorkItem = (PUMRX_USERMODE_WORKITEM) HeapAlloc(GetProcessHeap(), 0, SendSize);
if(pSendWorkItem == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//get a pointer to the response buffer
pSendBuffer = pSendWorkItem->WorkResponse.GetDfsReplicasResponse.Buffer;
pRef = (PRESP_GET_DFS_REFERRAL) pSendBuffer;
pRef->PathConsumed = (USHORT) pReferral->LinkNameLength;
//
// For level 1 referral, we fail if buffer is not big enough to
// fit entire referral. For level 2 and 3, we try to fit as many
// entries as possible into the refferal.
if(MaxLevel == 1)
{
if(Size < pGetReplicaRequest->RepInfo.ClientBufferSize)
{
DfspGetV1Referral(pReferral, pRef);
}
else
{
Status = ERROR_MORE_DATA;
}
}
else if(MaxLevel == 2)
{
Status = DfspGetV2Referral(pReferral, pGetReplicaRequest->RepInfo.ClientBufferSize, pRef,&Size);
}
else
{
Status = DfspGetV3Referral(pReferral, pGetReplicaRequest->RepInfo.ClientBufferSize, pRef ,&Size);
}
if(Status == ERROR_SUCCESS)
{
//copy the original header
pSendWorkItem->Header = ProtocolBuffer->Header;
pSendWorkItem->Header.IoStatus.Status = Status;
pSendWorkItem->Header.IoStatus.Information = 0;
//return without waiting for a response
pSendWorkItem->Header.ulFlags = UMR_WORKITEM_HEADER_FLAG_RETURN_IMMEDIATE;
//set the size of the data being returned
pSendWorkItem->WorkResponse.GetDfsReplicasResponse.Length = Size;
//finally send the data
Status = DfsUserModeProcessPacket(hDriverHandle,
(PBYTE) pSendWorkItem,
SendSize,
NULL,
0,
&BytesReturned);
}
if(pSendWorkItem != NULL)
{
HeapFree (GetProcessHeap(), 0, (PVOID) pSendWorkItem);
}
*ReturnedDataSize = Size;
return Status;
}