windows-nt/Source/XPSP1/NT/base/fs/dfs/lib/upkt.c

1092 lines
26 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: UPkt.c
//
// Contents: This module contains user mode functions which support
// operations on the DFS Partition Knowledge Table.
//
// Functions: PktOpen -
// PktClose -
// PktCreateEntry -
// PktCreateSubordinateEntry -
// PktFlushCache -
// PktDestroyEntry -
// PktModifyEntryGuid -
// PktSetRelationInfo -
//
// History:
//
// [mikese] I replaced MemAlloc's by malloc's, but consider using
// RtlAllocateHeap.
// Also, most of the routines in the module have a remarkably similar
// structure, and could probably be recoded using a common subroutine.
//
//-----------------------------------------------------------------------------
#include <ntifs.h>
#include <ntext.h>
#include "dfsmrshl.h"
#include "nodetype.h"
#include "libsup.h"
#include "upkt.h"
#include "dfsfsctl.h"
#include "fsctrl.h" // needed for FSCTL_DFS_PKT_FLUSH_CACHE
#define MAX_OUT_BUFFER_SIZE_RELINFO 0x1000
//+-------------------------------------------------------------------------
//
// Function: PktOpen, public
//
// Synopsis: Returns a handle to the Dfs PKT so operations can be made
// to it.
//
// Arguments:
//
// Returns: [STATUS_SUCCESS] -- Successfully opened the pkt.
//
// [STATUS_FS_DRIVER_REQUIRED] -- Dfs driver not loaded
//
//--------------------------------------------------------------------------
NTSTATUS
PktOpen(
IN OUT PHANDLE PktHandle,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess,
IN PUNICODE_STRING DfsNtPathName OPTIONAL
)
{
NTSTATUS status;
HANDLE dfsHandle;
status = DfsOpen(&dfsHandle, DfsNtPathName);
if(NT_SUCCESS(status)) {
*PktHandle = dfsHandle;
} else {
status = STATUS_FS_DRIVER_REQUIRED;
}
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktClose, public
//
// Synopsis:
//
// Arguments:
//
// Returns: Nothing
//
//--------------------------------------------------------------------------
VOID
PktClose(
IN HANDLE PktHandle
)
{
NTSTATUS status = STATUS_SUCCESS;
if(NT_SUCCESS(status))
NtClose(PktHandle);
}
//+-------------------------------------------------------------------------
//
// Function: PktCreateEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS
PktCreateEntry(
IN HANDLE PktHandle,
IN ULONG EntryType,
IN PDFS_PKT_ENTRY_ID EntryId,
IN PDFS_PKT_ENTRY_INFO EntryInfo,
IN ULONG CreateDisposition
)
{
NTSTATUS status;
DFS_PKT_CREATE_ENTRY_ARG arg;
MARSHAL_BUFFER marshalBuffer;
ULONG size;
arg.EntryType = EntryType;
arg.EntryId = (*EntryId);
arg.EntryInfo = (*EntryInfo);
arg.CreateDisposition = CreateDisposition;
size = 0L;
status = DfsRtlSize(&MiPktCreateEntryArg, &arg, &size);
if(NT_SUCCESS(status))
{
PVOID buffer = malloc ( size );
if ( buffer == NULL )
return(STATUS_NO_MEMORY);
MarshalBufferInitialize(&marshalBuffer, size, buffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktCreateEntryArg,
&arg
);
if(NT_SUCCESS(status))
{
status = DfsFsctl(
PktHandle,
FSCTL_DFS_PKT_CREATE_ENTRY,
buffer,
size,
NULL,
0L
);
}
free(buffer);
}
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktCreateSubordinateEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS
PktCreateSubordinateEntry(
IN HANDLE PktHandle,
IN PDFS_PKT_ENTRY_ID SuperiorId,
IN ULONG SubordinateType,
IN PDFS_PKT_ENTRY_ID SubordinateId,
IN PDFS_PKT_ENTRY_INFO SubordinateInfo OPTIONAL,
IN ULONG CreateDisposition
)
{
NTSTATUS status;
DFS_PKT_CREATE_SUBORDINATE_ENTRY_ARG arg;
MARSHAL_BUFFER marshalBuffer;
ULONG size;
arg.EntryId = (*SuperiorId);
arg.SubEntryType = SubordinateType;
arg.SubEntryId = (*SubordinateId);
arg.SubEntryInfo = (*SubordinateInfo);
arg.CreateDisposition = CreateDisposition;
size = 0L;
status = DfsRtlSize(&MiPktCreateSubordinateEntryArg, &arg, &size);
if(NT_SUCCESS(status)) {
PVOID buffer = malloc ( size );
if ( buffer == NULL )
return(STATUS_NO_MEMORY);
MarshalBufferInitialize(&marshalBuffer, size, buffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktCreateSubordinateEntryArg,
&arg
);
if(NT_SUCCESS(status)) {
status = DfsFsctl(
PktHandle,
FSCTL_DFS_PKT_CREATE_SUBORDINATE_ENTRY,
buffer,
size,
NULL,
0L
);
}
free(buffer);
}
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktDestroyEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS
PktDestroyEntry(
IN HANDLE PktHandle,
IN DFS_PKT_ENTRY_ID victim
)
{
NTSTATUS status;
MARSHAL_BUFFER marshalBuffer;
ULONG size;
size = 0L;
status = DfsRtlSize(&MiPktEntryId, &victim, &size);
if(NT_SUCCESS(status))
{
PVOID buffer = malloc ( size );
if ( buffer == NULL )
return(STATUS_NO_MEMORY);
MarshalBufferInitialize(&marshalBuffer, size, buffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktEntryId,
&victim
);
if(NT_SUCCESS(status))
{
status = DfsFsctl(
PktHandle,
FSCTL_DFS_PKT_DESTROY_ENTRY,
buffer,
size,
NULL,
0L
);
}
free(buffer);
}
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktGetRelationInfo, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: The relationalInfo structure should be made available
// by the caller but additional memory is allocated in here.
// The caller should deallocate all that memory himself.
//
//--------------------------------------------------------------------------
NTSTATUS
PktGetRelationInfo(
IN HANDLE PktHandle,
IN PDFS_PKT_ENTRY_ID EntryId,
IN OUT PDFS_PKT_RELATION_INFO RelationInfo
)
{
NTSTATUS status;
MARSHAL_BUFFER marshalBuffer;
ULONG size;
PVOID OutputBuffer;
size = 0L;
status = DfsRtlSize(&MiPktEntryId, EntryId, &size);
if(NT_SUCCESS(status))
{
PVOID buffer = malloc ( size );
if ( buffer == NULL )
return(STATUS_NO_MEMORY);
MarshalBufferInitialize(&marshalBuffer, size, buffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktEntryId,
EntryId
);
if(NT_SUCCESS(status))
{
// Do we want to retry with larger sizes?
OutputBuffer = malloc ( MAX_OUT_BUFFER_SIZE_RELINFO );
if ( OutputBuffer == NULL )
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
status = DfsFsctl(
PktHandle,
FSCTL_DFS_PKT_GET_RELATION_INFO,
buffer,
size,
OutputBuffer,
MAX_OUT_BUFFER_SIZE_RELINFO);
//
// We can get rid of this right away.
//
if(NT_SUCCESS(status)) {
MarshalBufferInitialize(
&marshalBuffer,
MAX_OUT_BUFFER_SIZE_RELINFO,
OutputBuffer
);
status = DfsRtlGet(
&marshalBuffer,
&MiPktRelationInfo,
RelationInfo
);
}
free(OutputBuffer);
}
}
free(buffer);
} //Status from DfsRtlSize
if (!NT_SUCCESS(status)) {
RtlZeroMemory(RelationInfo, sizeof(DFS_PKT_RELATION_INFO));
}
return status;
}
//+----------------------------------------------------------------------------
//
// Function: PktValidateLocalVolumeInfo, public
//
// Synopsis: Asks the Dfs driver to validate its local volume info with
// the one that is passed in.
//
// Arguments: [relationInfo] -- The DFS_PKT_RELATION_INFO to validate
// against.
//
// Returns: [STATUS_SUCCESS] -- Successfully validated local volume info
//
// [STATUS_REGISTRY_RECOVERED] -- Successfully validated info,
// but had to make changes to local info
//
// [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- The driver has no record
// of local volume described in relation info.
//
// [STATUS_UNSUCCESSFUL] -- Unable to fixup the local relation
// info. An appropriate message was logged to the
// local eventlog.
//
// [STATUS_DATA_ERROR] -- Passed in relationInfo is bogus.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition.
//
// [STATUS_FS_DRIVER_REQUIRED] -- Unable to open handle to the
// Dfs driver
//
//-----------------------------------------------------------------------------
NTSTATUS
PktValidateLocalVolumeInfo(
IN PDFS_PKT_RELATION_INFO relationInfo)
{
NTSTATUS status;
HANDLE dfsHandle;
MARSHAL_BUFFER marshalBuffer;
PUCHAR pBuffer;
ULONG cbBuffer;
status = DfsOpen(&dfsHandle, NULL);
if (NT_SUCCESS(status)) {
cbBuffer = 0;
status = DfsRtlSize( &MiPktRelationInfo, relationInfo, &cbBuffer );
if (NT_SUCCESS(status)) {
pBuffer = malloc( cbBuffer );
if (pBuffer != NULL) {
MarshalBufferInitialize(&marshalBuffer, cbBuffer, pBuffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktRelationInfo,
relationInfo);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_VERIFY_LOCAL_VOLUME_KNOWLEDGE,
pBuffer,
cbBuffer,
NULL,
0);
}
if (pBuffer != NULL)
free(pBuffer);
}
NtClose( dfsHandle );
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: PktPruneLocalPartition
//
// Synopsis: Asks the Dfs Driver to get rid of a local volume that is
// not supposed to be supported by this server.
//
// Arguments: [EntryId] -- The entry id of the volume to prune.
//
// Returns: [STATUS_SUCCESS] -- Successfully pruned the volume
//
// [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- The driver has no record
// of local volume described in relation info.
//
// [STATUS_UNSUCCESSFUL] -- Unable to fixup the local relation
// info. An appropriate message was logged to the
// local eventlog.
//
// [STATUS_DATA_ERROR] -- Passed in relationInfo is bogus.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition.
//
// [STATUS_FS_DRIVER_REQUIRED] -- Unable to open handle to the
// Dfs driver
//
//-----------------------------------------------------------------------------
NTSTATUS
PktPruneLocalPartition(
IN PDFS_PKT_ENTRY_ID EntryId)
{
NTSTATUS status;
HANDLE dfsHandle;
MARSHAL_BUFFER marshalBuffer;
PUCHAR pBuffer;
ULONG cbBuffer;
status = DfsOpen(&dfsHandle, NULL);
if (NT_SUCCESS(status)) {
cbBuffer = 0;
status = DfsRtlSize( &MiPktEntryId, EntryId, &cbBuffer );
if (NT_SUCCESS(status)) {
pBuffer = malloc( cbBuffer );
if (pBuffer != NULL) {
MarshalBufferInitialize(&marshalBuffer, cbBuffer, pBuffer);
status = DfsRtlPut(
&marshalBuffer,
&MiPktEntryId,
EntryId);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_PRUNE_LOCAL_PARTITION,
pBuffer,
cbBuffer,
NULL,
0);
}
if (pBuffer != NULL)
free(pBuffer);
}
NtClose( dfsHandle );
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: PktIsChildnameLegal, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
PktIsChildnameLegal(
IN PWCHAR pwszParent,
IN PWCHAR pwszChild,
IN GUID *pidChild)
{
HANDLE dfsHandle;
NTSTATUS Status;
DFS_PKT_ENTRY_ID idParent, idChild;
MARSHAL_BUFFER marshalBuffer;
PUCHAR pBuffer;
ULONG cbBuffer;
RtlZeroMemory( &idParent, sizeof(DFS_PKT_ENTRY_ID) );
RtlZeroMemory( &idChild, sizeof(DFS_PKT_ENTRY_ID) );
RtlInitUnicodeString( &idParent.Prefix, pwszParent );
RtlInitUnicodeString( &idChild.Prefix, pwszChild );
idChild.Uid = *pidChild;
cbBuffer = 0;
Status = DfsOpen(&dfsHandle, NULL);
if (NT_SUCCESS(Status)) {
Status = DfsRtlSize( &MiPktEntryId, &idParent, &cbBuffer );
if (NT_SUCCESS(Status)) {
Status = DfsRtlSize( &MiPktEntryId, &idChild, &cbBuffer );
}
if (NT_SUCCESS(Status)) {
pBuffer = malloc( cbBuffer );
if (pBuffer != NULL) {
MarshalBufferInitialize( &marshalBuffer, cbBuffer, pBuffer );
Status = DfsRtlPut(
&marshalBuffer,
&MiPktEntryId,
&idParent );
if (NT_SUCCESS(Status)) {
Status = DfsRtlPut(
&marshalBuffer,
&MiPktEntryId,
&idChild );
}
if (NT_SUCCESS(Status)) {
Status = DfsFsctl(
dfsHandle,
FSCTL_DFS_IS_CHILDNAME_LEGAL,
pBuffer,
cbBuffer,
NULL,
0L);
}
free( pBuffer );
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
NtClose( dfsHandle );
}
return( Status );
}
//+----------------------------------------------------------------------------
//
// Function: PktGetEntryType, public
//
// Synopsis: Given a prefix, this routine retrieves the entry type of the
// PktEntry
//
// Arguments: [pwszPrefix] -- The prefix whose PktEntry's type is required
// [pType] -- The type is returned here.
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
PktGetEntryType(
IN PWSTR pwszPrefix,
IN PULONG pType)
{
HANDLE dfsHandle;
NTSTATUS Status;
Status = DfsOpen(&dfsHandle, NULL);
if (NT_SUCCESS(Status)) {
Status = DfsFsctl(
dfsHandle,
FSCTL_DFS_GET_ENTRY_TYPE,
pwszPrefix,
wcslen(pwszPrefix) * sizeof(WCHAR),
pType,
sizeof(ULONG));
NtClose( dfsHandle );
}
return( Status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsSetServiceState
//
// Synopsis: Sets the state of a service on a volume.
//
// Arguments: [VolumeId] -- The volume on which to operate
// [ServiceName] -- Name of service
// [State] -- Either 0 or DFS_SERVICE_TYPE_OFFLINE
//
// 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] -- marshalling or unmarshalling error.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
//
// Status from opening handle to the Dfs driver.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsSetServiceState(
IN PDFS_PKT_ENTRY_ID VolumeId,
IN PWSTR ServiceName,
IN ULONG State)
{
NTSTATUS status;
HANDLE dfsHandle = NULL;
DFS_DC_SET_SERVICE_STATE setSvcState;
MARSHAL_BUFFER marshalBuffer;
PUCHAR buffer = NULL;
ULONG size;
status = DfsOpen( &dfsHandle, NULL );
if (NT_SUCCESS(status)) {
setSvcState.Id = *VolumeId;
RtlInitUnicodeString(
&setSvcState.ServiceName,
ServiceName);
setSvcState.State = State;
size = 0;
status = DfsRtlSize( &MiDCSetServiceState, &setSvcState, &size );
if (NT_SUCCESS(status)) {
buffer = (PUCHAR) malloc( size );
if (buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(status)) {
MarshalBufferInitialize( &marshalBuffer, size, buffer );
status = DfsRtlPut( &
marshalBuffer,
&MiDCSetServiceState,
&setSvcState );
}
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_SET_SERVICE_STATE,
buffer,
size,
NULL,
0);
}
NtClose( dfsHandle );
if (buffer != NULL) {
free( buffer );
}
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsDCSetVolumeState
//
// Synopsis: Sets the state of a volume in the DCs. This will control
// whether referrals will be given out to this volume or not.
//
// Arguments: [VolumeId] -- The volume on which to operate
// [State] -- Either 0 or PKT_ENTRY_TYPE_OFFLINE
//
// 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] -- marshalling or unmarshalling error.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
//
// Status from opening handle to the Dfs driver.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsDCSetVolumeState(
IN const PDFS_PKT_ENTRY_ID VolumeId,
IN const ULONG State)
{
NTSTATUS status;
HANDLE dfsHandle = NULL;
DFS_SETSTATE_ARG setStateArg;
MARSHAL_BUFFER marshalBuffer;
PUCHAR buffer = NULL;
ULONG size;
status = DfsOpen( &dfsHandle, NULL );
if (NT_SUCCESS(status)) {
setStateArg.Id = *VolumeId;
setStateArg.Type = State;
size = 0;
status = DfsRtlSize( &MiSetStateArg, &setStateArg, &size );
if (NT_SUCCESS(status)) {
buffer = (PUCHAR) malloc( size );
if (buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(status)) {
MarshalBufferInitialize( &marshalBuffer, size, buffer );
status = DfsRtlPut( &
marshalBuffer,
&MiSetStateArg,
&setStateArg );
}
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_DC_SET_VOLUME_STATE,
buffer,
size,
NULL,
0);
}
NtClose( dfsHandle );
if (buffer != NULL) {
free( buffer );
}
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsSetVolumeTimeout
//
// Synopsis: Sets the timeout of a volume in the DCs.
//
// Arguments: [VolumeId] -- The volume on which to operate
// [Timeout] -- Timeout, in seconds
//
// Returns: [STATUS_SUCCESS] -- The specified timeout was set as specified.
//
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
// found.
//
// [STATUS_DATA_ERROR] -- marshalling or unmarshalling error.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
//
// Status from opening handle to the Dfs driver.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsSetVolumeTimeout(
IN const PDFS_PKT_ENTRY_ID VolumeId,
IN const ULONG Timeout)
{
NTSTATUS status;
HANDLE dfsHandle = NULL;
DFS_SET_VOLUME_TIMEOUT_ARG setVolTimeoutArg;
MARSHAL_BUFFER marshalBuffer;
PUCHAR buffer = NULL;
ULONG size;
status = DfsOpen( &dfsHandle, NULL );
if (NT_SUCCESS(status)) {
setVolTimeoutArg.Id = *VolumeId;
setVolTimeoutArg.Timeout = Timeout;
size = 0;
status = DfsRtlSize( &MiSetVolTimeoutArg, &setVolTimeoutArg, &size );
if (NT_SUCCESS(status)) {
buffer = (PUCHAR) malloc( size );
if (buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(status)) {
MarshalBufferInitialize( &marshalBuffer, size, buffer );
status = DfsRtlPut( &
marshalBuffer,
&MiSetVolTimeoutArg,
&setVolTimeoutArg );
}
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_SET_VOLUME_TIMEOUT,
buffer,
size,
NULL,
0);
}
NtClose( dfsHandle );
if (buffer != NULL) {
free( buffer );
}
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsCreateSiteEntry
//
// Synopsis: Loads a Site entry into the dfs site table
//
// Arguments: [pInfoArg] -- DFS_CREATE_SITE_INFO_ARG with info to update
//
// Returns: Status from opening handle to the Dfs driver.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsCreateSiteEntry(
PCHAR arg,
ULONG size)
{
NTSTATUS status;
HANDLE dfsHandle = NULL;
status = DfsOpen( &dfsHandle, NULL );
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_CREATE_SITE_INFO,
arg,
size,
NULL,
0);
NtClose( dfsHandle );
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteSiteEntry
//
// Synopsis: Loads a Site entry into the dfs site table
//
// Arguments: [pInfoArg] -- DFS_DELETE_SITE_INFO_ARG with info to update
//
// Returns: Status from opening handle to the Dfs driver.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsDeleteSiteEntry(
PCHAR arg,
ULONG size)
{
NTSTATUS status;
HANDLE dfsHandle = NULL;
status = DfsOpen( &dfsHandle, NULL );
if (NT_SUCCESS(status)) {
status = DfsFsctl(
dfsHandle,
FSCTL_DFS_DELETE_SITE_INFO,
arg,
size,
NULL,
0);
NtClose( dfsHandle );
}
return( status );
}