Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

328 lines
8.9 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
MountSup.c
Abstract:
This module implements the support routines in Ntfs for reparse points.
Author:
Felipe Cabrera [cabrera] 30-Jun-1997
Revision History:
--*/
#include "NtfsProc.h"
#define Dbg DEBUG_TRACE_FSCTRL
//
// Define a tag for general pool allocations from this module
//
#undef MODULE_POOL_TAG
#define MODULE_POOL_TAG ('PFtN')
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NtfsInitializeReparsePointIndex)
#pragma alloc_text(PAGE, NtfsValidateReparsePointBuffer)
#endif
VOID
NtfsInitializeReparsePointIndex (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN PVCB Vcb
)
/*++
Routine Description:
This routine opens the mount points index for the volume. If the index does not
exist it is created and initialized.
Arguments:
Fcb - Pointer to Fcb for the object id file.
Vcb - Volume control block for volume being mounted.
Return Value:
None
--*/
{
UNICODE_STRING IndexName = CONSTANT_UNICODE_STRING( L"$R" );
PAGED_CODE();
NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
try {
NtOfsCreateIndex( IrpContext,
Fcb,
IndexName,
CREATE_OR_OPEN,
0,
COLLATION_NTOFS_ULONGS,
NtOfsCollateUlongs,
NULL,
&Vcb->ReparsePointTableScb );
} finally {
NtfsReleaseFcb( IrpContext, Fcb );
}
}
NTSTATUS
NtfsValidateReparsePointBuffer (
IN ULONG BufferLength,
IN PREPARSE_DATA_BUFFER ReparseBuffer
)
/*++
Routine Description:
This routine verifies that the reparse point buffer is valid.
Arguments:
BufferLength - Length of the reparse point buffer.
ReparseBuffer - The reparse point buffer to be validated.
Return Value:
NTSTATUS - The return status for the operation.
If successful, STATUS_SUCCESS will be returned.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG ReparseTag;
USHORT ReparseDataLength;
PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer;
PAGED_CODE();
//
// Be defensive about the length of the buffer before re-referencing it.
//
ASSERT( REPARSE_DATA_BUFFER_HEADER_SIZE < REPARSE_GUID_DATA_BUFFER_HEADER_SIZE );
if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE) {
//
// Return invalid buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Data in buffer is too short.\n") );
return Status;
}
//
// Return if the buffer is too long.
//
if (BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
//
// Return invalid buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Data in buffer is too long.\n") );
return Status;
}
//
// Get the header information brought in the buffer.
// While all the headers coincide in the layout of the first three fields we are home free.
//
ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
ReparseTag = ReparseBuffer->ReparseTag;
ReparseDataLength = ReparseBuffer->ReparseDataLength;
ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = [x]%08lx [d]%08ld\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
//
// Verify that the buffer and the data length in its header are
// internally consistent. We need to have a REPARSE_DATA_BUFFER or a
// REPARSE_GUID_DATA_BUFFER.
//
if (((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) != BufferLength) &&
((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) != BufferLength)) {
//
// Return invalid buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Buffer is not self-consistent.\n") );
return Status;
}
//
// Sanity check the buffer size combination reserved for Microsoft tags.
//
if ((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) == BufferLength) {
//
// This buffer length can only be used with Microsoft tags.
//
if (!IsReparseTagMicrosoft( ReparseTag )) {
//
// Return buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Wrong reparse tag in Microsoft buffer.\n") );
return Status;
}
}
//
// Sanity check the buffer size combination that has a GUID.
//
if ((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) == BufferLength) {
//
// If the tag is a non-Microsoft tag, then the GUID cannot be NULL
//
if (!IsReparseTagMicrosoft( ReparseTag )) {
if ((ReparseGuidBuffer->ReparseGuid.Data1 == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data2 == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data3 == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[0] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[1] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[2] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[3] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[4] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[5] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[6] == 0) &&
(ReparseGuidBuffer->ReparseGuid.Data4[7] == 0)) {
//
// Return invalid buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("The GUID is null for a non-Microsoft reparse tag.\n") );
return Status;
}
}
//
// This kind of buffer cannot be used for name grafting operations.
//
if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
//
// Return invalid buffer parameter error.
//
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Attempt to use the GUID buffer for name grafting.\n") );
return Status;
}
}
//
// We verify that the caller has zeroes in all the reserved bits and that she
// sets one of the non-reserved tags. Also fail if the tag is the retired NSS
// flag.
//
if ((ReparseTag & ~IO_REPARSE_TAG_VALID_VALUES) ||
(ReparseTag == IO_REPARSE_TAG_RESERVED_ZERO) ||
(ReparseTag == IO_REPARSE_TAG_RESERVED_ONE)) {
Status = STATUS_IO_REPARSE_TAG_INVALID;
DebugTrace( 0, Dbg, ("Reparse tag is an reserved one.\n") );
return Status;
}
//
// NTFS directory junctions are only to be set at directories and have a valid buffer.
//
if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
//
// Valid ReparseBuffer must have
//
// 1) Enough space for the length fields
// 2) A correct substitute name offset
// 3) A print name offset following the substitute name
// 4) enough space for the path name and substitute name
//
if ((ReparseBuffer->ReparseDataLength <
(FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE)) ||
(ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset != 0) ||
(ReparseBuffer->MountPointReparseBuffer.PrintNameOffset !=
(ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof( UNICODE_NULL ))) ||
(ReparseBuffer->ReparseDataLength !=
(FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE) +
ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
ReparseBuffer->MountPointReparseBuffer.PrintNameLength +
2 * sizeof( UNICODE_NULL ))) {
Status = STATUS_IO_REPARSE_DATA_INVALID;
DebugTrace( 0, Dbg, ("Invalid mount point reparse buffer.\n") );
return Status;
}
}
return Status;
}