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