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
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|