877 lines
24 KiB
C
877 lines
24 KiB
C
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Copyright (C) 1995, Microsoft Corporation
|
|||
|
//
|
|||
|
// File: dcfsctl.c
|
|||
|
//
|
|||
|
// Contents: This file has all the fsctrl routines that typically execute
|
|||
|
// on a DC.
|
|||
|
//
|
|||
|
// Classes:
|
|||
|
//
|
|||
|
// Functions: DfsFsctrlDCSetVolumeState -
|
|||
|
// DfsFsctrlDCSetVolumeState -
|
|||
|
// DfsFsctrlSetServiceState -
|
|||
|
// DfsFsctrlGetServerInfo -
|
|||
|
// DfsFsctrlCheckStgIdInUse -
|
|||
|
//
|
|||
|
// DfspGetServerConfigInfo -
|
|||
|
// IsPathAPrefixOf -
|
|||
|
//
|
|||
|
//
|
|||
|
// History: April 5, 1995 Milans created
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
#include "dfsprocs.h"
|
|||
|
#include <dfserr.h>
|
|||
|
#include <netevent.h>
|
|||
|
#include "fsctrl.h"
|
|||
|
#include "log.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfspGetServerConfigInfo(
|
|||
|
IN GUID *pMachine,
|
|||
|
IN PDFS_PKT pPkt,
|
|||
|
IN PDFS_PKT_ENTRY pPktEntry,
|
|||
|
OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IsPathAPrefixOf(
|
|||
|
IN PUNICODE_STRING pustrPath1,
|
|||
|
IN PUNICODE_STRING pustrPath2);
|
|||
|
|
|||
|
#pragma alloc_text( PAGE, DfsFsctrlDCSetVolumeState )
|
|||
|
#pragma alloc_text( PAGE, DfsFsctrlSetVolumeTimeout )
|
|||
|
#pragma alloc_text( PAGE, DfsFsctrlSetServiceState )
|
|||
|
#pragma alloc_text( PAGE, DfsFsctrlGetServerInfo )
|
|||
|
#pragma alloc_text( PAGE, DfsFsctrlCheckStgIdInUse )
|
|||
|
|
|||
|
#pragma alloc_text( PAGE, DfspGetServerConfigInfo )
|
|||
|
#pragma alloc_text( PAGE, IsPathAPrefixOf )
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_LOCALVOL)
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsctrlDCSetVolumeState, public
|
|||
|
//
|
|||
|
// Synopsis: Marks the specified replica offline for the particular volume
|
|||
|
//
|
|||
|
// Arguments: [Irp]
|
|||
|
//
|
|||
|
// [InputBuffer] -- Marshalled DFS_SETSTATE_ARG structure
|
|||
|
// that specifies the volume and the state to set it to.
|
|||
|
//
|
|||
|
// [InputBufferLength] -- Length in bytes of InputBuffer
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- The specified replica was set
|
|||
|
// online/offline as speficied.
|
|||
|
//
|
|||
|
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
|||
|
// found.
|
|||
|
//
|
|||
|
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
|||
|
// correctly unmarshalled.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsFsctrlDCSetVolumeState(
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID InputBuffer,
|
|||
|
IN ULONG InputBufferLength)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
MARSHAL_BUFFER marshalBuffer;
|
|||
|
DFS_SETSTATE_ARG setStateArg;
|
|||
|
PDFS_PKT pkt;
|
|||
|
PDFS_PKT_ENTRY pktEntry;
|
|||
|
|
|||
|
STD_FSCTRL_PROLOGUE(DfsFsctrlDCSetVolumeState, TRUE, FALSE);
|
|||
|
|
|||
|
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
|||
|
|
|||
|
status = DfsRtlGet(
|
|||
|
&marshalBuffer,
|
|||
|
&MiSetStateArg,
|
|||
|
&setStateArg);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugTrace(
|
|||
|
0, Dbg, "Setting volume state for %[wZ]\n",
|
|||
|
&setStateArg.Id.Prefix);
|
|||
|
|
|||
|
pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireShared( pkt, TRUE );
|
|||
|
|
|||
|
pktEntry = PktLookupEntryById( pkt, &setStateArg.Id );
|
|||
|
|
|||
|
if (pktEntry != NULL) {
|
|||
|
|
|||
|
if (setStateArg.Type == PKT_ENTRY_TYPE_OFFLINE) {
|
|||
|
|
|||
|
pktEntry->Type |= PKT_ENTRY_TYPE_OFFLINE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
pktEntry->Type &= ~PKT_ENTRY_TYPE_OFFLINE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
|||
|
|
|||
|
status = DFS_STATUS_NO_SUCH_ENTRY;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PktRelease( pkt );
|
|||
|
|
|||
|
PktEntryIdDestroy(&setStateArg.Id, FALSE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsctrlDCSetVolumeState: Exit %08lx\n", ULongToPtr( status ));
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, status );
|
|||
|
|
|||
|
return( status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsctrlSetServiceState, public
|
|||
|
//
|
|||
|
// Synopsis: Marks the specified replica offline for the particular volume
|
|||
|
//
|
|||
|
// Arguments: [Irp]
|
|||
|
//
|
|||
|
// [InputBuffer] -- Marshalled DFS_DC_SET_REPLICA_STATE structure
|
|||
|
// that specifies the volume and the replica to be set
|
|||
|
// offline/online.
|
|||
|
//
|
|||
|
// [InputBufferLength] -- Length in bytes of InputBuffer
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- The specified replica was set
|
|||
|
// online/offline as speficied.
|
|||
|
//
|
|||
|
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
|||
|
// found, or the specified replica is not a server for
|
|||
|
// the volume.
|
|||
|
//
|
|||
|
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
|||
|
// correctly unmarshalled.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsFsctrlSetServiceState(
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID InputBuffer,
|
|||
|
IN ULONG InputBufferLength)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
MARSHAL_BUFFER marshalBuffer;
|
|||
|
DFS_DC_SET_SERVICE_STATE setSvcState;
|
|||
|
PDFS_PKT pkt;
|
|||
|
PDFS_PKT_ENTRY pktEntry;
|
|||
|
|
|||
|
STD_FSCTRL_PROLOGUE(DfsFsctrlSetServiceState, TRUE, FALSE);
|
|||
|
|
|||
|
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
|||
|
|
|||
|
status = DfsRtlGet(
|
|||
|
&marshalBuffer,
|
|||
|
&MiDCSetServiceState,
|
|||
|
&setSvcState);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugTrace(
|
|||
|
0, Dbg, "Setting service state for [%wZ]\n",
|
|||
|
&setSvcState.Id.Prefix);
|
|||
|
|
|||
|
DebugTrace(
|
|||
|
0, Dbg, "For Service [%wZ]\n", &setSvcState.ServiceName);
|
|||
|
|
|||
|
pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireShared( pkt, TRUE );
|
|||
|
|
|||
|
pktEntry = PktLookupEntryById( pkt, &setSvcState.Id );
|
|||
|
|
|||
|
if (pktEntry != NULL) {
|
|||
|
|
|||
|
PDFS_SERVICE pSvc;
|
|||
|
ULONG i, cSvc;
|
|||
|
|
|||
|
status = DFS_STATUS_NO_SUCH_ENTRY;
|
|||
|
|
|||
|
for (i = 0, cSvc = pktEntry->Info.ServiceCount;
|
|||
|
i < cSvc && status != STATUS_SUCCESS;
|
|||
|
i++) {
|
|||
|
|
|||
|
pSvc = &pktEntry->Info.ServiceList[i];
|
|||
|
|
|||
|
if (RtlEqualUnicodeString(
|
|||
|
&setSvcState.ServiceName, &pSvc->Name, TRUE)) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Found Svc @ %08lx\n", pSvc );
|
|||
|
|
|||
|
if (setSvcState.State == DFS_SERVICE_TYPE_OFFLINE) {
|
|||
|
|
|||
|
pSvc->Type |= DFS_SERVICE_TYPE_OFFLINE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
pSvc->Type &= ~DFS_SERVICE_TYPE_OFFLINE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} // For each service
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
|||
|
|
|||
|
status = DFS_STATUS_NO_SUCH_ENTRY;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PktRelease( pkt );
|
|||
|
|
|||
|
//
|
|||
|
// Free up the unmarshalled arguments
|
|||
|
//
|
|||
|
|
|||
|
PktEntryIdDestroy(&setSvcState.Id, FALSE);
|
|||
|
MarshalBufferFree( setSvcState.ServiceName.Buffer );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsctrlSetServiceState: Exit %08lx\n", ULongToPtr( status ));
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, status );
|
|||
|
|
|||
|
return( status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsctrlSetVolumeTimeout, public
|
|||
|
//
|
|||
|
// Synopsis: Sets the specified volume's referral timeout
|
|||
|
//
|
|||
|
// Arguments: [Irp]
|
|||
|
//
|
|||
|
// [InputBuffer] -- Marshalled DFS_SET_VOLUME_TIMEOUT_ARG structure
|
|||
|
// that specifies the volume and the timeout to associate
|
|||
|
// with the volume.
|
|||
|
//
|
|||
|
// [InputBufferLength] -- Length in bytes of InputBuffer
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- The specified timeout was set.
|
|||
|
//
|
|||
|
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
|||
|
// found.
|
|||
|
//
|
|||
|
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
|||
|
// correctly unmarshalled.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsFsctrlSetVolumeTimeout(
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID InputBuffer,
|
|||
|
IN ULONG InputBufferLength)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
MARSHAL_BUFFER marshalBuffer;
|
|||
|
DFS_SET_VOLUME_TIMEOUT_ARG setVolTimeoutArg;
|
|||
|
PDFS_PKT pkt;
|
|||
|
PDFS_PKT_ENTRY pktEntry;
|
|||
|
|
|||
|
STD_FSCTRL_PROLOGUE(DfsFsctrlSetVolumeTimeout, TRUE, FALSE);
|
|||
|
|
|||
|
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
|||
|
|
|||
|
status = DfsRtlGet(
|
|||
|
&marshalBuffer,
|
|||
|
&MiSetVolTimeoutArg,
|
|||
|
&setVolTimeoutArg);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugTrace(
|
|||
|
0, Dbg, "Setting volume timeout for %[wZ]\n",
|
|||
|
&setVolTimeoutArg.Id.Prefix);
|
|||
|
|
|||
|
pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireShared( pkt, TRUE );
|
|||
|
|
|||
|
pktEntry = PktLookupEntryById( pkt, &setVolTimeoutArg.Id );
|
|||
|
|
|||
|
if (pktEntry != NULL) {
|
|||
|
|
|||
|
pktEntry->Info.Timeout = setVolTimeoutArg.Timeout;
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
|||
|
|
|||
|
status = DFS_STATUS_NO_SUCH_ENTRY;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PktRelease( pkt );
|
|||
|
|
|||
|
//
|
|||
|
// Free the unmarshalled input arguments
|
|||
|
//
|
|||
|
|
|||
|
PktEntryIdDestroy(&setVolTimeoutArg.Id, FALSE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsctrlSetVolumeTimeout: Exit %08lx\n", ULongToPtr( status ));
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, status );
|
|||
|
|
|||
|
return( status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsctrlGetServerInfo
|
|||
|
//
|
|||
|
// Synopsis: Given the machine guid of a server, this routine will return
|
|||
|
// the entire local volume knowledge that a dfs server should
|
|||
|
// have. This routine is intended to be called on the DC only.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- The info is successfully returned.
|
|||
|
//
|
|||
|
// [STATUS_BUFFER_OVERFLOW] -- The output buffer is too small.
|
|||
|
// The needed size is returned in the first 4 bytes of
|
|||
|
// this buffer.
|
|||
|
//
|
|||
|
// [STATUS_DATA_ERROR] -- The input buffer could not be
|
|||
|
// unmarshalled
|
|||
|
//
|
|||
|
// [STATUS_BUFFER_TOO_SMALL] -- The output buffer is < 4 bytes.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsFsctrlGetServerInfo(
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID InputBuffer,
|
|||
|
IN ULONG InputBufferLength,
|
|||
|
IN PVOID OutputBuffer,
|
|||
|
IN ULONG OutputBufferLength)
|
|||
|
{
|
|||
|
NTSTATUS Status, MarshalStatus;
|
|||
|
PDFS_PKT pPkt;
|
|||
|
PDFS_PKT_ENTRY pPktEntry;
|
|||
|
MARSHAL_BUFFER marshalBuffer;
|
|||
|
DFS_PKT_ENTRY_ID EntryId;
|
|||
|
DFS_LOCAL_VOLUME_CONFIG ConfigInfo;
|
|||
|
ULONG i, cInfo, cbBuffer;
|
|||
|
|
|||
|
STD_FSCTRL_PROLOGUE(DfsFsctrlGetServerInfo, TRUE, FALSE);
|
|||
|
|
|||
|
pPkt = _GetPkt();
|
|||
|
|
|||
|
//
|
|||
|
// Get the input arguments
|
|||
|
//
|
|||
|
|
|||
|
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
|||
|
|
|||
|
Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &EntryId );
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"Getting Server Info for server [%wZ]\n", &EntryId.Prefix);
|
|||
|
|
|||
|
MarshalBufferInitialize(
|
|||
|
&marshalBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
OutputBuffer );
|
|||
|
|
|||
|
//
|
|||
|
// We'll marshal in a count of 0 at the beginning of the output
|
|||
|
// buffer. Later, we'll revisit this and put in the actual count of
|
|||
|
// relation info's.
|
|||
|
//
|
|||
|
|
|||
|
cInfo = 0;
|
|||
|
|
|||
|
MarshalStatus = DfsRtlPutUlong( &marshalBuffer, &cInfo );
|
|||
|
|
|||
|
cbBuffer = sizeof(ULONG);
|
|||
|
|
|||
|
//
|
|||
|
// For each Pkt entry, create and marshal a relation info if the
|
|||
|
// Dfs volume is a local volume for the server.
|
|||
|
//
|
|||
|
|
|||
|
PktAcquireShared( pPkt, TRUE );
|
|||
|
|
|||
|
pPktEntry =
|
|||
|
CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
|
|||
|
|
|||
|
for (i = 0; i < pPkt->EntryCount && NT_SUCCESS(Status); i++) {
|
|||
|
|
|||
|
Status = DfspGetServerConfigInfo(
|
|||
|
&EntryId.Uid,
|
|||
|
pPkt,
|
|||
|
pPktEntry,
|
|||
|
&ConfigInfo);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Found [%wZ]\n", &pPktEntry->Id.Prefix);
|
|||
|
|
|||
|
Status = DfsRtlSize( &MiLocalVolumeConfig, &ConfigInfo, &cbBuffer);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && NT_SUCCESS(MarshalStatus)) {
|
|||
|
|
|||
|
MarshalStatus = DfsRtlPut(
|
|||
|
&marshalBuffer,
|
|||
|
&MiLocalVolumeConfig,
|
|||
|
&ConfigInfo);
|
|||
|
|
|||
|
cInfo++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LocalVolumeConfigInfoDestroy( &ConfigInfo, FALSE );
|
|||
|
|
|||
|
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|||
|
|
|||
|
//
|
|||
|
// Means volume is not local to server - go on to the next
|
|||
|
// Pkt Entry
|
|||
|
//
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else if (Status == STATUS_OBJECT_TYPE_MISMATCH) {
|
|||
|
|
|||
|
//
|
|||
|
// Means volume is a Machine, Domain, or Orgroot volume -
|
|||
|
// we ignore it.
|
|||
|
//
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"Error %08lx constructing relation info!\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
pPktEntry =
|
|||
|
CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
|
|||
|
|
|||
|
} // End for each Pkt Entry
|
|||
|
|
|||
|
PktRelease( pPkt );
|
|||
|
|
|||
|
//
|
|||
|
// Free the unmarshalled input arguments
|
|||
|
//
|
|||
|
|
|||
|
PktEntryIdDestroy(&EntryId, FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace( 0, Dbg, "Error %08lx unmarshalling input\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
if (NT_SUCCESS(MarshalStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Everything went successfully - Marshal in the number of
|
|||
|
// relation info's we are returning at the beginning of the
|
|||
|
// output buffer
|
|||
|
//
|
|||
|
|
|||
|
MarshalBufferInitialize(
|
|||
|
&marshalBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
OutputBuffer);
|
|||
|
|
|||
|
Status = DfsRtlPutUlong( &marshalBuffer, &cInfo );
|
|||
|
|
|||
|
ASSERT( NT_SUCCESS(Status) );
|
|||
|
|
|||
|
ASSERT( cbBuffer <= OutputBufferLength );
|
|||
|
|
|||
|
Irp->IoStatus.Information = cbBuffer;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If we hit a marshalling error along the way, we'll try and
|
|||
|
// tell the caller how much buffer we need
|
|||
|
//
|
|||
|
|
|||
|
RETURN_BUFFER_SIZE( cbBuffer, Status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, Status );
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsctrlGetServerInfo: returning %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsctrlCheckStgIdInUse
|
|||
|
//
|
|||
|
// Synopsis: Given a storage id and the machine guid of a server, this
|
|||
|
// routine will say whether the storage id can be legally shared
|
|||
|
// by the server. This routine is intended to be called on the
|
|||
|
// DC only.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- It is legal for the server to share the
|
|||
|
// storage id.
|
|||
|
//
|
|||
|
// [STATUS_DEVICE_BUSY] -- Some parent or child of the
|
|||
|
// storage id is already shared in Dfs. The shared
|
|||
|
// volume is returned in OutputBuffer.
|
|||
|
//
|
|||
|
// [STATUS_BUFFER_OVERFLOW] -- OutputBuffer too small to return
|
|||
|
// prefix of shared volume - the required size is
|
|||
|
// returned in the first 4 bytes of OutputBuffer
|
|||
|
//
|
|||
|
// [STATUS_BUFFER_TOO_SMALL] -- OutputBuffer is < 4 bytes.
|
|||
|
//
|
|||
|
// [STATUS_DATA_ERROR] -- Unable to unmarshall the arguments.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to unmarshall the
|
|||
|
// arguments.
|
|||
|
//
|
|||
|
// Notes: The Input buffer is a marshalled PKT_ENTRY_ID, where the
|
|||
|
// GUID is the server's machine id, and the Prefix is the
|
|||
|
// storage id to be verified.
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsFsctrlCheckStgIdInUse(
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID InputBuffer,
|
|||
|
IN ULONG InputBufferLength,
|
|||
|
IN PVOID OutputBuffer,
|
|||
|
IN ULONG OutputBufferLength)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS; // Innocent till proven...
|
|||
|
PDFS_PKT pPkt;
|
|||
|
PDFS_PKT_ENTRY pPktEntry;
|
|||
|
MARSHAL_BUFFER marshalBuffer;
|
|||
|
DFS_PKT_ENTRY_ID EntryId;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
STD_FSCTRL_PROLOGUE(DfsFsctrlIsStgIdLegalOnServer, TRUE, FALSE);
|
|||
|
|
|||
|
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
|||
|
|
|||
|
Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &EntryId );
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Verifying Storage Id [%wZ]\n", &EntryId.Prefix );
|
|||
|
|
|||
|
pPkt = _GetPkt();
|
|||
|
|
|||
|
pPktEntry =
|
|||
|
CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
|
|||
|
|
|||
|
for (i = 0; i < pPkt->EntryCount && NT_SUCCESS(Status); i++) {
|
|||
|
|
|||
|
//
|
|||
|
// For every pkt entry, we iterate through all the services. If a
|
|||
|
// service matches the input service, then we see if the storage
|
|||
|
// id is a prefix or child of the service's storage id. If so,
|
|||
|
// the storage id is not legal.
|
|||
|
//
|
|||
|
|
|||
|
ULONG j;
|
|||
|
|
|||
|
for (j = 0;
|
|||
|
j < pPktEntry->Info.ServiceCount && NT_SUCCESS(Status);
|
|||
|
j++) {
|
|||
|
|
|||
|
PDFS_SERVICE pService = &pPktEntry->Info.ServiceList[j];
|
|||
|
|
|||
|
if ( GuidEqual( &pService->pMachEntry->pMachine->guidMachine,
|
|||
|
&EntryId.Uid ) ) {
|
|||
|
|
|||
|
|
|||
|
if (IsPathAPrefixOf(
|
|||
|
&EntryId.Prefix,
|
|||
|
&pService->StgId ) ||
|
|||
|
IsPathAPrefixOf(
|
|||
|
&pService->StgId,
|
|||
|
&EntryId.Prefix )) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"Stg Id Not legal - Conflicts with [%wZ]\n",
|
|||
|
&pPktEntry->Id.Prefix);
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"Storage Id for share is [%wZ]\n",
|
|||
|
&pService->StgId);
|
|||
|
|
|||
|
Status = STATUS_DEVICE_BUSY;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We found a matching service, no need to look at the
|
|||
|
// rest of the services
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
pPktEntry =
|
|||
|
CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the unmarshalled input arguments
|
|||
|
//
|
|||
|
|
|||
|
PktEntryIdDestroy(&EntryId, FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace( 0, Dbg, "Unmarshalling Error - %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, Status );
|
|||
|
|
|||
|
DebugTrace(-1, Dbg,
|
|||
|
"DfsFsctrlIsStgIdLegalOnServer - returning %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfspGetServerConfigInfo
|
|||
|
//
|
|||
|
// Synopsis: Given a machine guid and a pkt entry, this routine will
|
|||
|
// return the relation info for the entry if the machine is a
|
|||
|
// server for the entry.
|
|||
|
//
|
|||
|
// Arguments: [pMachine] -- Pointer to machine guid
|
|||
|
// [pPkt] -- The pkt to examine
|
|||
|
// [pPktEntry] -- The pkt entry to examine
|
|||
|
// [pConfigInfo] -- If the machine is a server for this entry, a
|
|||
|
// relation info is returned here.
|
|||
|
//
|
|||
|
// Returns: [STATUS_SUCCESS] -- Machine is a server, and relation info
|
|||
|
// constructed successfully
|
|||
|
//
|
|||
|
// [STATUS_OBJECT_NAME_NOT_FOUND] -- Machine is not a server for
|
|||
|
// the given pkt entry
|
|||
|
//
|
|||
|
// [STATUS_OBJECT_TYPE_MISMATCH] -- pPktEntry is for a machine,
|
|||
|
// domain, or orgroot volume. Can't get config info for
|
|||
|
// these volumes.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Machine is a server, but
|
|||
|
// out of memory constructing relation info
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfspGetServerConfigInfo(
|
|||
|
IN GUID *pMachine,
|
|||
|
IN PDFS_PKT pPkt,
|
|||
|
IN PDFS_PKT_ENTRY pPktEntry,
|
|||
|
OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo)
|
|||
|
{
|
|||
|
ULONG j;
|
|||
|
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
|
|||
|
//
|
|||
|
// We can't get a config info for a machine volume.
|
|||
|
//
|
|||
|
|
|||
|
if ( ((pPktEntry->Type & PKT_ENTRY_TYPE_MACHINE) != 0) ||
|
|||
|
(pPktEntry == pPkt->DomainPktEntry) ||
|
|||
|
(pPktEntry->Id.Prefix.Length == sizeof(WCHAR))) {
|
|||
|
|
|||
|
return( STATUS_OBJECT_TYPE_MISMATCH );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
for (j = 0; j < pPktEntry->Info.ServiceCount; j++) {
|
|||
|
|
|||
|
PDFS_SERVICE pService = &pPktEntry->Info.ServiceList[j];
|
|||
|
|
|||
|
if ( GuidEqual(
|
|||
|
&pService->pMachEntry->pMachine->guidMachine,
|
|||
|
pMachine ) ) {
|
|||
|
|
|||
|
Status = PktRelationInfoConstruct(
|
|||
|
&pConfigInfo->RelationInfo,
|
|||
|
pPkt,
|
|||
|
&pPktEntry->Id);
|
|||
|
|
|||
|
ASSERT( Status != DFS_STATUS_NO_SUCH_ENTRY );
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
ASSERT( pService->StgId.Length != 0 );
|
|||
|
|
|||
|
pConfigInfo->StgId.Length = 0;
|
|||
|
pConfigInfo->StgId.MaximumLength =
|
|||
|
pService->StgId.MaximumLength;
|
|||
|
pConfigInfo->StgId.Buffer = ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
pService->StgId.Length,
|
|||
|
' sfD');
|
|||
|
|
|||
|
if (pConfigInfo->StgId.Buffer != NULL) {
|
|||
|
|
|||
|
RtlCopyUnicodeString(
|
|||
|
&pConfigInfo->StgId,
|
|||
|
&pService->StgId);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
ASSERT( pPktEntry->Type & PKT_ENTRY_TYPE_CAIRO );
|
|||
|
|
|||
|
//
|
|||
|
// Send only the PKT_ENTRY_TYPE_CAIRO bit.
|
|||
|
//
|
|||
|
|
|||
|
pConfigInfo->EntryType = PKT_ENTRY_TYPE_CAIRO;
|
|||
|
|
|||
|
//
|
|||
|
// Send only the service online/offline bit
|
|||
|
//
|
|||
|
|
|||
|
pConfigInfo->ServiceType = pService->Type &
|
|||
|
DFS_SERVICE_TYPE_OFFLINE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( Status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: IsPathAPrefixOf
|
|||
|
//
|
|||
|
// Synopsis: Given two paths, this will return TRUE if the first path is
|
|||
|
// a prefix of the second.
|
|||
|
//
|
|||
|
// Arguments: [pustrPath1] -- The two paths
|
|||
|
// [pustrPath2]
|
|||
|
//
|
|||
|
// Returns: TRUE if pustrPath1 is a prefix of pustrPath2, FALSE otherwise
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IsPathAPrefixOf(
|
|||
|
IN PUNICODE_STRING pustrPath1,
|
|||
|
IN PUNICODE_STRING pustrPath2)
|
|||
|
{
|
|||
|
BOOLEAN fResult;
|
|||
|
|
|||
|
fResult = RtlPrefixUnicodeString( pustrPath1, pustrPath2, FALSE );
|
|||
|
|
|||
|
if (fResult) {
|
|||
|
|
|||
|
//
|
|||
|
// Path1 is a prefix of Path2. However, this is not a sufficient test.
|
|||
|
// We have to catch cases like d:\test1 being a prefix of d:\test10
|
|||
|
//
|
|||
|
|
|||
|
fResult =
|
|||
|
(pustrPath2->Length == pustrPath1->Length)
|
|||
|
||
|
|||
|
(pustrPath2->Buffer[ pustrPath1->Length / sizeof(WCHAR) ] ==
|
|||
|
UNICODE_PATH_SEP);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( fResult );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|