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