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.
2144 lines
58 KiB
2144 lines
58 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
create.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the file create routine for the MUP.
|
|
|
|
Author:
|
|
|
|
Manny Weiser (mannyw) 16-Dec-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mup.h"
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CREATE)
|
|
|
|
//
|
|
// Local functions
|
|
//
|
|
|
|
NTSTATUS
|
|
CreateRedirectedFile(
|
|
IN PIRP Irp,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PIO_SECURITY_CONTEXT Security
|
|
);
|
|
|
|
NTSTATUS
|
|
QueryPathCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
MupRerouteOpenToDfs (
|
|
IN PFILE_OBJECT FileObject
|
|
);
|
|
|
|
NTSTATUS
|
|
BroadcastOpen (
|
|
IN PIRP Irp
|
|
);
|
|
|
|
IO_STATUS_BLOCK
|
|
OpenMupFileSystem (
|
|
IN PVCB Vcb,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN USHORT ShareAccess
|
|
);
|
|
|
|
NTSTATUS
|
|
IsThisASysVolPath(
|
|
IN PUNICODE_STRING PathName,
|
|
IN PUNICODE_STRING DCName);
|
|
|
|
NTSTATUS
|
|
MupDomainToDC(
|
|
PUNICODE_STRING RootName,
|
|
PUNICODE_STRING DCName);
|
|
|
|
BOOLEAN
|
|
MupFlushPrefixEntry (
|
|
PUNICODE_STRING pathName
|
|
);
|
|
|
|
VOID
|
|
MupInvalidatePrefixTable (
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
DfspIsSysVolShare(
|
|
PUNICODE_STRING ShareName);
|
|
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, BroadcastOpen )
|
|
#pragma alloc_text( PAGE, CreateRedirectedFile )
|
|
#pragma alloc_text( PAGE, MupCreate )
|
|
#pragma alloc_text( PAGE, MupRerouteOpenToDfs )
|
|
#pragma alloc_text( PAGE, OpenMupFileSystem )
|
|
#pragma alloc_text( PAGE, QueryPathCompletionRoutine )
|
|
#pragma alloc_text( PAGE, MupFlushPrefixEntry)
|
|
#pragma alloc_text( PAGE, MupInvalidatePrefixTable)
|
|
#pragma alloc_text( PAGE, IsThisASysVolPath)
|
|
#pragma alloc_text( PAGE, MupDomainToDC)
|
|
#ifdef TERMSRV
|
|
#pragma alloc_text( PAGE, TSGetRequestorSessionId )
|
|
#endif // TERMSRV
|
|
#endif
|
|
|
|
#ifdef TERMSRV
|
|
|
|
NTSTATUS
|
|
TSGetRequestorSessionId(
|
|
IN PIRP pIrp,
|
|
OUT PULONG pulSessionId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the session ID for user that is creating a file
|
|
via the IRP_MJ_CREATE, IRP_MJ_CREATE_NAMED_PIPE or IRP_MJ_CREATE_MAILSLOT
|
|
IRP requests.
|
|
|
|
Arguments:
|
|
|
|
pIrp - pointer to the I/O Request Packet.
|
|
|
|
pulSessionId - pointer to the session Id which is set upon successful
|
|
return.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - if the session ID was available.
|
|
STATUS_UNSUCCESSFUL - otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
PFILE_OBJECT FileObject = pIrpSp->FileObject;
|
|
PIO_SECURITY_CONTEXT pSecurityContext;
|
|
PSECURITY_SUBJECT_CONTEXT pSecSubjectContext;
|
|
UNICODE_STRING FileName = FileObject->FileName;
|
|
|
|
switch (pIrpSp->MajorFunction) {
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CREATE_NAMED_PIPE:
|
|
case IRP_MJ_CREATE_MAILSLOT:
|
|
pSecurityContext = pIrpSp->Parameters.Create.SecurityContext;
|
|
break;
|
|
|
|
#if 0
|
|
case IRP_MJ_CREATE_NAMED_PIPE:
|
|
pSecurityContext = pIrpSp->Parameters.CreatePipe.SecurityContext;
|
|
break;
|
|
|
|
case IRP_MJ_CREATE_MAILSLOT:
|
|
pSecurityContext = pIrpSp->Parameters.CreateMailslot.SecurityContext;
|
|
break;
|
|
#endif // 0
|
|
|
|
default:
|
|
pSecurityContext = NULL;
|
|
break;
|
|
}
|
|
|
|
if ( pSecurityContext == NULL ) {
|
|
*pulSessionId = (ULONG) INVALID_SESSIONID;
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
MUP_TRACE_HIGH(ERROR, TSGetRequestorSessionId_Error1,
|
|
LOGSTATUS(ntStatus)
|
|
LOGPTR(pIrp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
pSecSubjectContext = &pSecurityContext->AccessState->SubjectSecurityContext;
|
|
|
|
ntStatus = SeQuerySessionIdToken(
|
|
((pSecSubjectContext->ClientToken != NULL) ?
|
|
pSecSubjectContext->ClientToken :
|
|
pSecSubjectContext->PrimaryToken ),
|
|
pulSessionId);
|
|
Cleanup:
|
|
|
|
if( !NT_SUCCESS( ntStatus ) ) {
|
|
DebugTrace(0, Dbg,
|
|
"TSGetRequestorSessionId returns error, 0x%lx\n",
|
|
ntStatus);
|
|
}
|
|
else {
|
|
DebugTrace(0, Dbg,
|
|
"TSGetRequestorSessionId returns SessionID, %ld\n",
|
|
*pulSessionId);
|
|
}
|
|
|
|
return(ntStatus);
|
|
|
|
}
|
|
|
|
|
|
#endif // TERMSRV
|
|
|
|
|
|
NTSTATUS
|
|
MupCreate (
|
|
IN PMUP_DEVICE_OBJECT MupDeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the the Create IRP.
|
|
|
|
Arguments:
|
|
|
|
MupDeviceObject - Supplies the device object to use.
|
|
|
|
Irp - Supplies the Irp being processed
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status for the IRP.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
PFILE_OBJECT fileObject;
|
|
PFILE_OBJECT relatedFileObject;
|
|
STRING fileName;
|
|
ACCESS_MASK desiredAccess;
|
|
USHORT shareAccess;
|
|
LARGE_INTEGER StartTime;
|
|
LARGE_INTEGER EndTime;
|
|
|
|
BOOLEAN caseInsensitive = TRUE; //**** Make all searches case insensitive
|
|
PVCB vcb;
|
|
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(+1, Dbg, "MupCreate\n", 0);
|
|
|
|
//
|
|
// Make local copies of our input parameters to make things easier.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fileObject = irpSp->FileObject;
|
|
relatedFileObject = irpSp->FileObject->RelatedFileObject;
|
|
fileName = *((PSTRING)(&irpSp->FileObject->FileName));
|
|
desiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
|
shareAccess = irpSp->Parameters.Create.ShareAccess;
|
|
vcb = &MupDeviceObject->Vcb;
|
|
|
|
DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp );
|
|
DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)fileObject );
|
|
DebugTrace( 0, Dbg, "FileName = %Z\n", (ULONG)&fileName );
|
|
|
|
|
|
MUP_TRACE_HIGH(TRACE_IRP, MupCreate_Entry,
|
|
LOGPTR(MupDeviceObject)
|
|
LOGPTR(fileObject)
|
|
LOGPTR(Irp)
|
|
LOGUSTR(fileName));
|
|
|
|
KeQuerySystemTime(&StartTime);
|
|
#if DBG
|
|
if (MupVerbose) {
|
|
KeQuerySystemTime(&EndTime);
|
|
DbgPrint("[%d] MupCreate(%wZ)\n",
|
|
(ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
|
|
&fileObject->FileName);
|
|
}
|
|
#endif
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
try {
|
|
|
|
//
|
|
// Check to see if this is an open that came in via a Dfs device
|
|
// object.
|
|
//
|
|
|
|
if (MupEnableDfs) {
|
|
if ((MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) ||
|
|
(MupDeviceObject->DeviceObject.DeviceType ==
|
|
FILE_DEVICE_DFS_FILE_SYSTEM)) {
|
|
|
|
status = DfsFsdCreate( (PDEVICE_OBJECT) MupDeviceObject, Irp );
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_DfsFsdCreate,
|
|
LOGSTATUS(status)
|
|
LOGPTR(fileObject)
|
|
LOGPTR(Irp));
|
|
try_return( NOTHING );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if we are trying to open the mup file system
|
|
//
|
|
|
|
if ( fileName.Length == 0
|
|
&&
|
|
( relatedFileObject == NULL ||
|
|
BlockType(relatedFileObject->FsContext) == BlockTypeVcb ) ) {
|
|
|
|
DebugTrace(0, Dbg, "Open MUP file system\n", 0);
|
|
|
|
Irp->IoStatus = OpenMupFileSystem( &MupDeviceObject->Vcb,
|
|
fileObject,
|
|
desiredAccess,
|
|
shareAccess );
|
|
|
|
status = Irp->IoStatus.Status;
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_OpenMupFileSystem,
|
|
LOGSTATUS(status)
|
|
LOGPTR(fileObject)
|
|
LOGPTR(Irp));
|
|
|
|
MupCompleteRequest( Irp, status );
|
|
try_return( NOTHING );
|
|
}
|
|
|
|
//
|
|
// This is a UNC file open. Try to pass the request on.
|
|
//
|
|
|
|
status = CreateRedirectedFile(
|
|
Irp,
|
|
fileObject,
|
|
irpSp->Parameters.Create.SecurityContext
|
|
);
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_CreateRedirectedFile,
|
|
LOGSTATUS(status)
|
|
LOGPTR(fileObject)
|
|
LOGPTR(Irp));
|
|
|
|
try_exit: NOTHING;
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
// we need to complete the IRP.
|
|
// But first, get the error code.
|
|
status = GetExceptionCode();
|
|
MupCompleteRequest( Irp, status );
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
MUP_TRACE_HIGH(TRACE_IRP, MupCreate_Exit,
|
|
LOGSTATUS(status)
|
|
LOGPTR(fileObject)
|
|
LOGPTR(Irp));
|
|
DebugTrace(-1, Dbg, "MupCreate -> %08lx\n", status);
|
|
#if DBG
|
|
if (MupVerbose) {
|
|
KeQuerySystemTime(&EndTime);
|
|
DbgPrint("[%d] MupCreate exit 0x%x\n",
|
|
(ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
|
|
status);
|
|
}
|
|
#endif
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
IO_STATUS_BLOCK
|
|
OpenMupFileSystem (
|
|
IN PVCB Vcb,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN USHORT ShareAccess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to open the VCB.
|
|
|
|
Arguments:
|
|
|
|
Vcb - A pointer to the MUP volume control block.
|
|
|
|
FileObject - A pointer to the IO system supplied file object for this
|
|
Create IRP.
|
|
|
|
DesiredAccess - The user specified desired access to the VCB.
|
|
|
|
ShareAccess - The user specified share access to the VCB.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status for the IRP.
|
|
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(+1, Dbg, "MupOpenMupFileSystem\n", 0 );
|
|
MUP_TRACE_LOW(DEFAULT, OpenMupFileSystem_Entry,
|
|
LOGPTR(Vcb)
|
|
LOGPTR(FileObject)
|
|
LOGULONG(DesiredAccess)
|
|
LOGXSHORT(ShareAccess));
|
|
|
|
|
|
ExAcquireResourceExclusiveLite( &MupVcbLock, TRUE );
|
|
|
|
try {
|
|
|
|
//
|
|
// Set the new share access
|
|
//
|
|
|
|
if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
|
|
ShareAccess,
|
|
FileObject,
|
|
&Vcb->ShareAccess,
|
|
TRUE ))) {
|
|
|
|
DebugTrace(0, Dbg, "bad share access\n", 0);
|
|
MUP_TRACE_ERROR_HIGH(iosb.Status, ALL_ERROR, OpenMupFileSystem_Error_IoCheckShareAccess,
|
|
LOGSTATUS(iosb.Status)
|
|
LOGPTR(FileObject));
|
|
try_return( NOTHING );
|
|
}
|
|
|
|
//
|
|
// Supply the file object with a referenced pointer to the VCB.
|
|
//
|
|
|
|
MupReferenceBlock( Vcb );
|
|
MupSetFileObject( FileObject, Vcb, NULL );
|
|
|
|
//
|
|
// Set the return status.
|
|
//
|
|
|
|
iosb.Status = STATUS_SUCCESS;
|
|
iosb.Information = FILE_OPENED;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
ExReleaseResourceLite( &MupVcbLock );
|
|
|
|
}
|
|
|
|
//
|
|
// Return to the caller.
|
|
//
|
|
|
|
MUP_TRACE_LOW(DEFAULT, OpenMupFileSystem_Exit,
|
|
LOGSTATUS(iosb.Status)
|
|
LOGPTR(FileObject));
|
|
DebugTrace(-1, Dbg, "MupOpenMupFileSystem -> Iosb.Status = %08lx\n", iosb.Status);
|
|
return iosb;
|
|
}
|
|
|
|
NTSTATUS
|
|
CreateRedirectedFile(
|
|
IN PIRP Irp,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PIO_SECURITY_CONTEXT SecurityContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to reroute a file create request to a redirector.
|
|
It attempts to find the correct redirector in 2 steps.
|
|
|
|
(1) The routine checks a list of known prefixes. If the file object -
|
|
file name prefix matches a known prefix, the request is forwarded to
|
|
the redirector that "owns" the prefix.
|
|
|
|
(2) The routine queries each redirector in turn, until one claims
|
|
ownership of the file. The request is then rerouted to that redirector.
|
|
|
|
If after these steps no owner is located, the MUP fails the request.
|
|
|
|
Arguments:
|
|
|
|
Irp - A pointer to the create IRP.
|
|
|
|
FileObject - A pointer to the IO system supplied file object for this
|
|
create request.
|
|
|
|
SecurityContext - A pointer to the IO security context for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status for the IRP.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_BAD_NETWORK_PATH;
|
|
|
|
PUNICODE_PREFIX_TABLE_ENTRY entry;
|
|
PKNOWN_PREFIX knownPrefix = NULL;
|
|
PLIST_ENTRY listEntry;
|
|
PUNC_PROVIDER provider;
|
|
PWCH buffer;
|
|
LONG length;
|
|
BOOLEAN ownLock;
|
|
BOOLEAN providerReferenced = FALSE;
|
|
BOOLEAN firstProvider = TRUE;
|
|
|
|
PQUERY_PATH_REQUEST qpRequest;
|
|
|
|
PMASTER_QUERY_PATH_CONTEXT masterContext = NULL;
|
|
PQUERY_PATH_CONTEXT queryContext;
|
|
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
LARGE_INTEGER now;
|
|
UNICODE_STRING FileName = FileObject->FileName;
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(+1, Dbg, "CreateRedirectedFile\n", 0);
|
|
MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Entry,
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
|
|
// #ifdef TERMSRV
|
|
#if 0 // need to confirm with the citrix guys about this change.
|
|
|
|
if( IsTerminalServer() ) {
|
|
|
|
//
|
|
// Translate the filename for terminal server based on the session ID.
|
|
//
|
|
// NOTE: This re-allocates FileObject->FileName as needed
|
|
//
|
|
|
|
TSTranslateClientName( Irp, FileObject );
|
|
}
|
|
|
|
#endif // TERMSRV
|
|
|
|
//
|
|
// Handle empty filename
|
|
//
|
|
|
|
if (FileObject->FileName.Length == 0) {
|
|
|
|
MupCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST);
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_EmptyFilename,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject));
|
|
DebugTrace(-1, Dbg, "CreateRedirectedFile exit 0x%x\n", status);
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if this file name begins with a known prefix.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &MupPrefixTableLock );
|
|
|
|
entry = RtlFindUnicodePrefix( &MupPrefixTable, &FileObject->FileName, TRUE );
|
|
|
|
if ( entry != NULL ) {
|
|
|
|
DebugTrace(0, Dbg, "Prefix %Z is known, rerouting...\n", (PSTRING)&FileObject->FileName);
|
|
|
|
//
|
|
// This is a known file, forward appropriately
|
|
//
|
|
|
|
knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
|
|
|
|
KeQuerySystemTime( &now );
|
|
|
|
if ( now.QuadPart < knownPrefix->LastUsedTime.QuadPart ) {
|
|
|
|
//
|
|
// The known prefix has not timed out yet, recalculate the
|
|
// timeout time and reroute the open.
|
|
//
|
|
|
|
MupCalculateTimeout( &knownPrefix->LastUsedTime );
|
|
status = MupRerouteOpen( FileObject, knownPrefix->UncProvider );
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
DebugTrace(-1, Dbg, "CreateRedirectedFile -> %8lx", status );
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_MupRerouteOpen,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileObject->FileName));
|
|
|
|
if (status == STATUS_REPARSE)
|
|
Irp->IoStatus.Information = IO_REPARSE;
|
|
|
|
MupCompleteRequest( Irp, status );
|
|
return status;
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "Prefix %Z has timed out\n", (PSTRING)&FileObject->FileName);
|
|
|
|
//
|
|
// The known prefix has timed out, dereference it so that
|
|
// it will get removed from the table.
|
|
//
|
|
if ( knownPrefix->InTable ) {
|
|
MupRemoveKnownPrefixEntry( knownPrefix);
|
|
}
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
}
|
|
|
|
} else {
|
|
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
|
|
}
|
|
|
|
//
|
|
// Is this a client side mailslot file? It is if the file name
|
|
// is of the form \\server\mailslot\Anything, and this is a create
|
|
// operation.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
buffer = (PWCH)FileObject->FileName.Buffer;
|
|
length = FileObject->FileName.Length;
|
|
|
|
if ( *buffer == L'\\' && irpSp->MajorFunction == IRP_MJ_CREATE ) {
|
|
buffer++;
|
|
while ( (length -= sizeof(WCHAR)) > 0 && *buffer++ != L'\\' )
|
|
NOTHING;
|
|
length -= sizeof(WCHAR);
|
|
|
|
if (
|
|
length >= (sizeof(L"MAILSLOT") - sizeof(WCHAR))
|
|
&&
|
|
_wcsnicmp(
|
|
buffer,
|
|
L"Mailslot",
|
|
MIN(length/sizeof(WCHAR),(sizeof(L"MAILSLOT")-sizeof(WCHAR))/sizeof(WCHAR))) == 0
|
|
) {
|
|
|
|
//
|
|
// This is a mailslot file. Forward the create IRP to all
|
|
// redirectors that support broadcast.
|
|
//
|
|
|
|
DebugTrace(0, Dbg, "Prefix %Z is a mailslot\n", (ULONG)&FileObject->FileName);
|
|
|
|
status = BroadcastOpen( Irp );
|
|
if (status == STATUS_REPARSE)
|
|
Irp->IoStatus.Information = IO_REPARSE;
|
|
MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Exit_Mailslot,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
MupCompleteRequest( Irp, status );
|
|
DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if this is a Dfs name. If so, we'll handle it separately
|
|
//
|
|
|
|
if (MupEnableDfs &&
|
|
(FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))) {
|
|
UNICODE_STRING pathName;
|
|
UNICODE_STRING DCName;
|
|
|
|
status = DfsFsctrlIsThisADfsPath( &FileObject->FileName, FALSE, &pathName );
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
DebugTrace(-1, Dbg, "Rerouting open of [%wZ] to Dfs\n", &FileObject->FileName);
|
|
status = MupRerouteOpenToDfs(FileObject);
|
|
if (status == STATUS_REPARSE)
|
|
Irp->IoStatus.Information = IO_REPARSE;
|
|
MupCompleteRequest( Irp, status );
|
|
return( status );
|
|
|
|
}
|
|
|
|
//
|
|
// If special table is not init'ed, and this is \<domainname>\<specialname>,
|
|
// rewrite into \<dcname>\<specialname>
|
|
//
|
|
if (DfsData.Pkt.SpecialTable.SpecialEntryCount == 0) {
|
|
DCName.Buffer = NULL;
|
|
DCName.Length = DCName.MaximumLength = 0;
|
|
status = IsThisASysVolPath(&FileObject->FileName, &DCName);
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
UNICODE_STRING NewName = FileObject->FileName;
|
|
status = MupDomainToDC(&NewName, &DCName);
|
|
|
|
if (DCName.Buffer != NULL)
|
|
ExFreePool(DCName.Buffer);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
FileObject->FileName = NewName;
|
|
}
|
|
else
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We don't know who owns this file, query the redirectors in sequence
|
|
// until one works.
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
//
|
|
// Allocate the master context and knownprefix. If either allocation fails, we'll
|
|
// complete the irp with STATUS_INSUFFICIENT_RESOURCES
|
|
//
|
|
|
|
knownPrefix = MupAllocatePrefixEntry( 0 );
|
|
|
|
if (knownPrefix == NULL) {
|
|
MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
masterContext = MupAllocateMasterQueryContext();
|
|
|
|
if (masterContext == NULL) {
|
|
|
|
ExFreePool(knownPrefix);
|
|
|
|
MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
masterContext->OriginalIrp = Irp;
|
|
|
|
masterContext->FileObject = FileObject;
|
|
masterContext->Provider = NULL;
|
|
masterContext->KnownPrefix = knownPrefix;
|
|
masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
|
|
|
|
MupAcquireGlobalLock();
|
|
// for debugging: insert the Master Context into the global list.
|
|
InsertHeadList(&MupMasterQueryList, &masterContext->MasterQueryList);
|
|
MupReferenceBlock( knownPrefix );
|
|
MupReleaseGlobalLock();
|
|
|
|
try {
|
|
|
|
MupAcquireGlobalLock();
|
|
ownLock = TRUE;
|
|
|
|
listEntry = MupProviderList.Flink;
|
|
while ( listEntry != &MupProviderList ) {
|
|
|
|
provider = CONTAINING_RECORD(
|
|
listEntry,
|
|
UNC_PROVIDER,
|
|
ListEntry
|
|
);
|
|
|
|
//
|
|
// Reference the provider block so that it doesn't go away
|
|
// while we are using it.
|
|
//
|
|
|
|
MupReferenceBlock( provider );
|
|
providerReferenced = TRUE;
|
|
|
|
MupReleaseGlobalLock();
|
|
ownLock = FALSE;
|
|
|
|
// only use this provider if it is registered
|
|
if(provider->Registered) {
|
|
|
|
//
|
|
// Allocate buffers for the io request.
|
|
//
|
|
|
|
qpRequest = NULL;
|
|
queryContext = NULL;
|
|
|
|
qpRequest = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
sizeof( QUERY_PATH_REQUEST ) +
|
|
FileObject->FileName.Length,
|
|
' puM');
|
|
|
|
if (qpRequest == NULL) {
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
queryContext = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
sizeof( QUERY_PATH_CONTEXT ),
|
|
' puM');
|
|
|
|
if (queryContext == NULL) {
|
|
ExFreePool(qpRequest);
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
InitializeListHead(&queryContext->QueryList);
|
|
queryContext->MasterContext = masterContext;
|
|
queryContext->Buffer = qpRequest;
|
|
|
|
//
|
|
// Generate a query path request.
|
|
//
|
|
|
|
qpRequest->PathNameLength = FileObject->FileName.Length;
|
|
qpRequest->SecurityContext = SecurityContext;
|
|
|
|
RtlMoveMemory(
|
|
qpRequest->FilePathName,
|
|
FileObject->FileName.Buffer,
|
|
FileObject->FileName.Length
|
|
);
|
|
|
|
//
|
|
// Build the query path Io control IRP.
|
|
//
|
|
|
|
irp = MupBuildIoControlRequest(
|
|
NULL,
|
|
provider->FileObject,
|
|
queryContext,
|
|
IRP_MJ_DEVICE_CONTROL,
|
|
IOCTL_REDIR_QUERY_PATH,
|
|
qpRequest,
|
|
sizeof( QUERY_PATH_REQUEST ) + FileObject->FileName.Length,
|
|
qpRequest,
|
|
sizeof( QUERY_PATH_RESPONSE ),
|
|
QueryPathCompletionRoutine
|
|
);
|
|
|
|
if ( irp == NULL ) {
|
|
ExFreePool(qpRequest);
|
|
ExFreePool(queryContext);
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
//
|
|
// Set the RequestorMode to KernelMode, since all the
|
|
// parameters to this Irp are in kernel space
|
|
//
|
|
|
|
irp->RequestorMode = KernelMode;
|
|
|
|
//
|
|
// Get a referenced pointer to the provider, the reference
|
|
// is release when the IO completes.
|
|
//
|
|
|
|
queryContext->Provider = provider;
|
|
queryContext->QueryIrp = irp;
|
|
|
|
MupAcquireGlobalLock();
|
|
MupReferenceBlock( provider );
|
|
MupReferenceBlock( masterContext );
|
|
MupReleaseGlobalLock();
|
|
|
|
|
|
// insert this query into the master context's list of queries (for debugging)
|
|
ACQUIRE_LOCK( &masterContext->Lock );
|
|
InsertHeadList(&masterContext->QueryList, &queryContext->QueryList);
|
|
RELEASE_LOCK( &masterContext->Lock );
|
|
|
|
//
|
|
// Submit the request.
|
|
//
|
|
|
|
MUP_TRACE_HIGH(ALL_ERROR, CreateRedirectedFile_Before_IoCallDriver,
|
|
LOGPTR(masterContext->OriginalIrp)
|
|
LOGPTR(queryContext->QueryIrp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName)
|
|
LOGUSTR(provider->DeviceName));
|
|
status = IoCallDriver( provider->DeviceObject, irp );
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_IoCallDriver,
|
|
LOGSTATUS(status)
|
|
LOGPTR(masterContext->OriginalIrp)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(provider->DeviceName));
|
|
|
|
} // if registered
|
|
|
|
//
|
|
// Acquire the lock that protects the provider list, and get
|
|
// a pointer to the next provider in the list.
|
|
//
|
|
|
|
MupAcquireGlobalLock();
|
|
ownLock = TRUE;
|
|
listEntry = listEntry->Flink;
|
|
|
|
MupDereferenceUncProvider( provider );
|
|
providerReferenced = FALSE;
|
|
|
|
//
|
|
// If this is the first provider and it responded with SUCCESS, we can return early.
|
|
// The list of providers is sorted in order of priority, so we know that this is
|
|
// the highest prority provider and it can get to the destination.
|
|
//
|
|
|
|
if( firstProvider && (status == STATUS_SUCCESS) ) {
|
|
break;
|
|
}
|
|
|
|
firstProvider = FALSE;
|
|
|
|
} // while
|
|
|
|
} finally {
|
|
|
|
//
|
|
// Dereference the previous provider.
|
|
//
|
|
|
|
if ( providerReferenced ) {
|
|
MupDereferenceUncProvider( provider );
|
|
}
|
|
|
|
if ( ownLock ) {
|
|
MupReleaseGlobalLock();
|
|
}
|
|
}
|
|
|
|
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
masterContext->ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ASSERT(masterContext != NULL);
|
|
|
|
//
|
|
// Release our reference to the query context.
|
|
//
|
|
|
|
MupDereferenceMasterQueryContext( masterContext );
|
|
|
|
status = STATUS_PENDING;
|
|
|
|
MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Exit,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject));
|
|
DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MupRerouteOpen (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PUNC_PROVIDER UncProvider
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine redirects an create IRP request to the specified redirector
|
|
by changing the name of the file and returning STATUS_REPARSE to the
|
|
IO system
|
|
|
|
Arguments:
|
|
|
|
FileObject - The file object to open
|
|
|
|
UncProvider - The UNC provider that will process the create IRP.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR buffer;
|
|
ULONG deviceNameLength;
|
|
ULONG nameLength;
|
|
NTSTATUS status;
|
|
UNICODE_STRING FileName = FileObject->FileName;
|
|
//
|
|
// Check that we won't create a name that is too long
|
|
//
|
|
|
|
nameLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
|
|
|
|
if (nameLength > MAXUSHORT) {
|
|
status = STATUS_NAME_TOO_LONG;
|
|
MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error1,
|
|
LOGSTATUS(status)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
return STATUS_NAME_TOO_LONG;
|
|
}
|
|
|
|
//
|
|
// Allocate storage for the new file name.
|
|
//
|
|
|
|
buffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
UncProvider->DeviceName.Length + FileObject->FileName.Length,
|
|
' puM');
|
|
|
|
if ( buffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error2,
|
|
LOGSTATUS(status)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Copy the device name to the string buffer.
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
buffer,
|
|
UncProvider->DeviceName.Buffer,
|
|
UncProvider->DeviceName.Length);
|
|
|
|
deviceNameLength = UncProvider->DeviceName.Length;
|
|
|
|
//
|
|
// Append the file name
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
buffer + deviceNameLength,
|
|
FileObject->FileName.Buffer,
|
|
FileObject->FileName.Length);
|
|
|
|
//
|
|
// Free the old file name string buffer.
|
|
//
|
|
|
|
ExFreePool( FileObject->FileName.Buffer );
|
|
|
|
FileObject->FileName.Buffer = (PWCHAR)buffer;
|
|
FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
|
|
FileObject->FileName.Length = FileObject->FileName.MaximumLength;
|
|
|
|
//
|
|
// Tell the file system to try again.
|
|
//
|
|
|
|
return STATUS_REPARSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
MupRerouteOpenToDfs (
|
|
IN PFILE_OBJECT FileObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine redirects an create IRP request to the Dfs part of this
|
|
driver by changing the name of the file and returning
|
|
STATUS_REPARSE to the IO system
|
|
|
|
Arguments:
|
|
|
|
FileObject - The file object to open
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR buffer;
|
|
ULONG deviceNameLength;
|
|
ULONG nameLength;
|
|
NTSTATUS status;
|
|
UNICODE_STRING FileName = FileObject->FileName;
|
|
|
|
PAGED_CODE();
|
|
|
|
MUP_TRACE_NORM(TRACE_IRP, MupRerouteOpenToDfs_Entry,
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
|
|
#if DBG
|
|
if (MupVerbose)
|
|
DbgPrint("MupRerouteOpenToDfs(%wZ)\n", &FileObject->FileName);
|
|
#endif
|
|
|
|
deviceNameLength = sizeof(DFS_DEVICE_ROOT) - sizeof(UNICODE_NULL);
|
|
|
|
//
|
|
// Check that we won't create a name that is too long
|
|
//
|
|
|
|
nameLength = deviceNameLength + FileObject->FileName.Length;
|
|
|
|
if (nameLength > MAXUSHORT) {
|
|
status = STATUS_NAME_TOO_LONG;
|
|
MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error1,
|
|
LOGSTATUS(status)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
#if DBG
|
|
if (MupVerbose)
|
|
DbgPrint("MupRerouteOpenToDfs exit STATUS_NAME_TOO_LONG\n");
|
|
#endif
|
|
return STATUS_NAME_TOO_LONG;
|
|
}
|
|
|
|
//
|
|
// Allocate storage for the new file name.
|
|
//
|
|
|
|
buffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
sizeof(DFS_DEVICE_ROOT) + FileObject->FileName.Length,
|
|
' puM');
|
|
|
|
if ( buffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error2,
|
|
LOGSTATUS(status)
|
|
LOGPTR(FileObject)
|
|
LOGUSTR(FileName));
|
|
#if DBG
|
|
if (MupVerbose)
|
|
DbgPrint("MupRerouteOpenToDfs exit STATUS_INSUFFICIENT_RESOURCES\n");
|
|
#endif
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Copy the device name to the string buffer.
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
buffer,
|
|
DFS_DEVICE_ROOT,
|
|
sizeof(DFS_DEVICE_ROOT));
|
|
|
|
//
|
|
// Append the file name
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
buffer + deviceNameLength,
|
|
FileObject->FileName.Buffer,
|
|
FileObject->FileName.Length);
|
|
|
|
//
|
|
// Free the old file name string buffer.
|
|
//
|
|
|
|
ExFreePool( FileObject->FileName.Buffer );
|
|
|
|
FileObject->FileName.Buffer = (PWCHAR)buffer;
|
|
FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
|
|
FileObject->FileName.Length = FileObject->FileName.MaximumLength;
|
|
|
|
//
|
|
// Tell the file system to try again.
|
|
//
|
|
|
|
#if DBG
|
|
if (MupVerbose)
|
|
DbgPrint("MupRerouteOpenToDfs exit STATUS_REPARSE ->[%wZ]\n", &FileObject->FileName);
|
|
#endif
|
|
return STATUS_REPARSE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BroadcastOpen (
|
|
PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status for the IRP.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PFCB fcb;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PFILE_OBJECT fileObject;
|
|
BOOLEAN requestForwarded;
|
|
PLIST_ENTRY listEntry;
|
|
PUNC_PROVIDER uncProvider, previousUncProvider = NULL;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
PCCB ccb;
|
|
OBJECT_HANDLE_INFORMATION handleInformation;
|
|
HANDLE handle;
|
|
BOOLEAN lockHeld = FALSE;
|
|
BOOLEAN providerReferenced = FALSE;
|
|
ULONG Len;
|
|
UNICODE_STRING FileName;
|
|
|
|
NTSTATUS statusToReturn = STATUS_NO_SUCH_FILE;
|
|
ULONG priorityOfStatus = 0xFFFFFFFF;
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(+1, Dbg, "BroadcastOpen\n", 0 );
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
FileName = irpSp->FileObject->FileName;
|
|
try {
|
|
|
|
//
|
|
// Create a FCB for this file.
|
|
//
|
|
|
|
fcb = MupCreateFcb( );
|
|
|
|
if (fcb == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error1,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(irpSp->FileObject)
|
|
LOGUSTR(FileName));
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
try {
|
|
|
|
//
|
|
// Set the file object back pointers and our pointer to the
|
|
// server file object.
|
|
//
|
|
|
|
fileObject = irpSp->FileObject;
|
|
|
|
MupAcquireGlobalLock();
|
|
lockHeld = TRUE;
|
|
|
|
MupSetFileObject( fileObject,
|
|
fcb,
|
|
NULL );
|
|
|
|
fcb->FileObject = fileObject;
|
|
|
|
//
|
|
// Loop through the list of UNC providers and try to create the
|
|
// file on all file systems that support broadcast.
|
|
//
|
|
|
|
requestForwarded = FALSE;
|
|
|
|
listEntry = MupProviderList.Flink;
|
|
|
|
while ( listEntry != &MupProviderList ) {
|
|
|
|
uncProvider = CONTAINING_RECORD( listEntry, UNC_PROVIDER, ListEntry );
|
|
|
|
//
|
|
// Reference the provider so that it won't go away
|
|
//
|
|
|
|
MupReferenceBlock( uncProvider );
|
|
providerReferenced = TRUE;
|
|
|
|
MupReleaseGlobalLock();
|
|
lockHeld = FALSE;
|
|
|
|
Len = uncProvider->DeviceName.Length + fileObject->FileName.Length;
|
|
|
|
if ( uncProvider->MailslotsSupported && Len <= MAXUSHORT) {
|
|
|
|
//
|
|
// Build the rerouted file name, consisting of the file
|
|
// named we received appended to the UNC provider device
|
|
// name.
|
|
//
|
|
|
|
UNICODE_STRING fileName;
|
|
|
|
fileName.MaximumLength = fileName.Length = (USHORT) Len;
|
|
|
|
fileName.Buffer =
|
|
ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
fileName.MaximumLength,
|
|
' puM');
|
|
|
|
if (fileName.Buffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error2,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(fileObject)
|
|
LOGUSTR(FileName));
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
fileName.Buffer,
|
|
uncProvider->DeviceName.Buffer,
|
|
uncProvider->DeviceName.Length
|
|
);
|
|
|
|
RtlMoveMemory(
|
|
(PCHAR)fileName.Buffer + uncProvider->DeviceName.Length,
|
|
fileObject->FileName.Buffer,
|
|
fileObject->FileName.Length
|
|
);
|
|
|
|
|
|
//
|
|
// Attempt to open the file. Copy all of the information
|
|
// from the create IRP we received, masking off additional
|
|
// baggage that the IO system added along the way.
|
|
//
|
|
|
|
DebugTrace( 0, Dbg, "Attempt to open %Z\n", (ULONG)&fileName );
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&fileName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
0,
|
|
NULL // !!! Security
|
|
);
|
|
|
|
status = IoCreateFile(
|
|
&handle,
|
|
irpSp->Parameters.Create.SecurityContext->DesiredAccess & 0x1FF,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
NULL,
|
|
irpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
|
|
irpSp->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
|
|
FILE_OPEN,
|
|
irpSp->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
|
|
NULL, // Ea buffer
|
|
0, // Ea length
|
|
CreateFileTypeNone,
|
|
NULL, // parameters
|
|
IO_NO_PARAMETER_CHECKING
|
|
);
|
|
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_IoCreateFile,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(fileObject)
|
|
LOGUSTR(FileName));
|
|
ExFreePool( fileName.Buffer );
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
status = ioStatusBlock.Status;
|
|
|
|
|
|
ccb = MupCreateCcb( );
|
|
|
|
if (ccb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error3,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(fileObject)
|
|
LOGUSTR(FileName));
|
|
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
|
|
DebugTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
|
|
|
|
//
|
|
// 426184, need to check return code for errors.
|
|
//
|
|
status = ObReferenceObjectByHandle(
|
|
handle,
|
|
0,
|
|
NULL,
|
|
KernelMode,
|
|
(PVOID *)&ccb->FileObject,
|
|
&handleInformation );
|
|
MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_ObReferenceObjectByHandle,
|
|
LOGSTATUS(status)
|
|
LOGPTR(Irp)
|
|
LOGPTR(fileObject)
|
|
LOGUSTR(FileName));
|
|
|
|
ZwClose( handle );
|
|
}
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
ccb->DeviceObject =
|
|
IoGetRelatedDeviceObject( ccb->FileObject );
|
|
|
|
ccb->Fcb = fcb;
|
|
|
|
MupAcquireGlobalLock();
|
|
lockHeld = TRUE;
|
|
MupReferenceBlock( fcb );
|
|
MupReleaseGlobalLock();
|
|
lockHeld = FALSE;
|
|
|
|
//
|
|
// At least one provider will accept this mailslot
|
|
// request.
|
|
//
|
|
|
|
requestForwarded = TRUE;
|
|
|
|
//
|
|
// Keep a list of CCBs. Since we just created the FCB
|
|
// there is no need to use the lock to access the list.
|
|
//
|
|
|
|
InsertTailList( &fcb->CcbList, &ccb->ListEntry );
|
|
|
|
} else { // NT_SUCCESS( status ), IoCreateFile
|
|
|
|
DebugTrace( 0, Dbg, "Open attempt failed %8lx\n", status );
|
|
|
|
//
|
|
// Remember the status code if this is the highest
|
|
// priority provider so far. This code is returned if
|
|
// all providers fail the Create operation.
|
|
//
|
|
|
|
if ( uncProvider->Priority <= priorityOfStatus ) {
|
|
priorityOfStatus = uncProvider->Priority;
|
|
statusToReturn = status;
|
|
}
|
|
|
|
}
|
|
|
|
} // uncProvider->MailslotsSupported
|
|
|
|
MupAcquireGlobalLock();
|
|
lockHeld = TRUE;
|
|
|
|
listEntry = listEntry->Flink;
|
|
|
|
//
|
|
// It is now safe to dereference the previous provider.
|
|
//
|
|
|
|
MupDereferenceUncProvider( uncProvider );
|
|
providerReferenced = FALSE;
|
|
|
|
} // while
|
|
|
|
MupReleaseGlobalLock();
|
|
lockHeld = FALSE;
|
|
|
|
//
|
|
// And set our return status
|
|
//
|
|
|
|
if ( requestForwarded ) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = statusToReturn;
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "BroadcastOpen -> %08lx\n", status);
|
|
|
|
if ( providerReferenced ) {
|
|
MupDereferenceUncProvider( uncProvider );
|
|
}
|
|
|
|
if ( lockHeld ) {
|
|
MupReleaseGlobalLock();
|
|
}
|
|
|
|
//
|
|
// Now if we ever terminate the preceding try-statement with
|
|
// a status that is not successful and the FCB pointer
|
|
// is non-null then we need to deallocate the structure.
|
|
//
|
|
|
|
if (!NT_SUCCESS( status ) && fcb != NULL) {
|
|
MupFreeFcb( fcb );
|
|
}
|
|
|
|
}
|
|
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
NOTHING;
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
QueryPathCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine the querying a path. Cleanup our
|
|
IRP and complete the original IRP if necessary.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to target device object for the request.
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
Context - Caller-specified context parameter associated with IRP.
|
|
This is actually a pointer to a Work Context block.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
|
|
completion processing by IoCompleteRequest terminates its
|
|
operation. Otherwise, IoCompleteRequest continues with I/O
|
|
completion.
|
|
|
|
--*/
|
|
|
|
{
|
|
PQUERY_PATH_RESPONSE qpResponse;
|
|
PMASTER_QUERY_PATH_CONTEXT masterContext;
|
|
PQUERY_PATH_CONTEXT queryPathContext;
|
|
PCH buffer;
|
|
PKNOWN_PREFIX knownPrefix;
|
|
ULONG lengthAccepted;
|
|
NTSTATUS status;
|
|
|
|
DeviceObject; // prevent compiler warnings
|
|
|
|
queryPathContext = Context;
|
|
masterContext = queryPathContext->MasterContext;
|
|
|
|
qpResponse = queryPathContext->Buffer;
|
|
lengthAccepted = qpResponse->LengthAccepted;
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
MUP_TRACE_NORM(TRACE_IRP, QueryPathCompletionRoutine_Enter,
|
|
LOGPTR(DeviceObject)
|
|
LOGPTR(Irp)
|
|
LOGUSTR(queryPathContext->Provider->DeviceName)
|
|
LOGPTR(masterContext->FileObject)
|
|
LOGUSTR(masterContext->FileObject->FileName)
|
|
LOGSTATUS(status)
|
|
);
|
|
|
|
//
|
|
// Acquire the lock to protect access to the master context Provider
|
|
// field.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &masterContext->Lock );
|
|
|
|
// remove this query from the MasterQueryContext's list.
|
|
RemoveEntryList(&queryPathContext->QueryList);
|
|
|
|
|
|
if (NT_SUCCESS(status) && lengthAccepted != 0) {
|
|
|
|
knownPrefix = masterContext->KnownPrefix;
|
|
|
|
if ( masterContext->Provider != NULL ) {
|
|
|
|
if ( queryPathContext->Provider->Priority < masterContext->Provider->Priority ) {
|
|
|
|
//
|
|
// A provider of higher priority (i.e. a lower priority code)
|
|
// has claimed this prefix. Release the previous provider's
|
|
// claim.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &MupPrefixTableLock );
|
|
|
|
if ( knownPrefix->InTable ) {
|
|
RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
|
|
RemoveEntryList(&knownPrefix->ListEntry);
|
|
knownPrefix->InTable = FALSE;
|
|
}
|
|
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
|
|
knownPrefix->Active = FALSE;
|
|
|
|
|
|
//
|
|
// If Dfs generated this query there will not have been anything
|
|
// stored in the knowPrefix->Prefix, so we check if there is indeed
|
|
// anything to free.
|
|
//
|
|
|
|
if (knownPrefix->Prefix.Length > 0 && knownPrefix->Prefix.Buffer != NULL) {
|
|
ExFreePool(knownPrefix->Prefix.Buffer);
|
|
knownPrefix->Prefix.Length = knownPrefix->Prefix.MaximumLength = 0;
|
|
knownPrefix->Prefix.Buffer = NULL;
|
|
knownPrefix->PrefixStringAllocated = FALSE;
|
|
}
|
|
if(knownPrefix->UncProvider) {
|
|
MupDereferenceUncProvider( knownPrefix->UncProvider );
|
|
knownPrefix->UncProvider = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The current provider keeps ownership of the prefix.
|
|
//
|
|
|
|
MupDereferenceUncProvider( queryPathContext->Provider );
|
|
goto not_this_one;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This provider gets the prefix.
|
|
//
|
|
|
|
masterContext->Provider = queryPathContext->Provider;
|
|
masterContext->ErrorStatus = status;
|
|
//
|
|
// We have found a match. Attempt to remember it.
|
|
//
|
|
|
|
if (masterContext->FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)) {
|
|
|
|
buffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
lengthAccepted,
|
|
' puM');
|
|
|
|
if (buffer != NULL) {
|
|
|
|
RtlMoveMemory(
|
|
buffer,
|
|
masterContext->FileObject->FileName.Buffer,
|
|
lengthAccepted
|
|
);
|
|
|
|
//
|
|
// Copy the reference provider pointer for the known prefix
|
|
// block.
|
|
//
|
|
|
|
knownPrefix->UncProvider = masterContext->Provider;
|
|
knownPrefix->Prefix.Buffer = (PWCH)buffer;
|
|
knownPrefix->Prefix.Length = (USHORT)lengthAccepted;
|
|
knownPrefix->Prefix.MaximumLength = (USHORT)lengthAccepted;
|
|
knownPrefix->PrefixStringAllocated = TRUE;
|
|
|
|
ACQUIRE_LOCK( &MupPrefixTableLock );
|
|
|
|
if (RtlInsertUnicodePrefix(
|
|
&MupPrefixTable,
|
|
&knownPrefix->Prefix,
|
|
&knownPrefix->TableEntry) == TRUE) {
|
|
|
|
InsertTailList( &MupPrefixList, &knownPrefix->ListEntry);
|
|
knownPrefix->InTable = TRUE;
|
|
knownPrefix->Active = TRUE;
|
|
|
|
} else {
|
|
|
|
knownPrefix->InTable = FALSE;
|
|
|
|
}
|
|
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
|
|
} else {
|
|
|
|
knownPrefix->InTable = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
MupDereferenceUncProvider( queryPathContext->Provider );
|
|
|
|
if (masterContext->Provider == NULL) {
|
|
|
|
//
|
|
// If our error status is more significant than the error status
|
|
// stored in the masterContext, then put ours there
|
|
//
|
|
|
|
ULONG newError, oldError;
|
|
|
|
//
|
|
// MupOrderedErrorList is a list of error codes ordered from least
|
|
// important to most important. We're calling down to multiple
|
|
// redirectors, but we can only return 1 error code on complete failure.
|
|
//
|
|
// To figure out which error to return, we look at the stored error and
|
|
// the current error. We return the error having the highest index in
|
|
// the MupOrderedErrorList
|
|
//
|
|
if( NT_SUCCESS( masterContext->ErrorStatus ) ) {
|
|
masterContext->ErrorStatus = status;
|
|
} else {
|
|
for( oldError = 0; MupOrderedErrorList[ oldError ]; oldError++ )
|
|
if( masterContext->ErrorStatus == MupOrderedErrorList[ oldError ] )
|
|
break;
|
|
|
|
for( newError = 0; newError < oldError; newError++ )
|
|
if( status == MupOrderedErrorList[ newError ] )
|
|
break;
|
|
|
|
if( newError >= oldError ) {
|
|
masterContext->ErrorStatus = status;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
not_this_one:
|
|
|
|
|
|
//
|
|
// Free our buffers
|
|
//
|
|
|
|
ExFreePool( qpResponse );
|
|
ExFreePool( queryPathContext );
|
|
IoFreeIrp( Irp );
|
|
|
|
|
|
|
|
|
|
RELEASE_LOCK( &masterContext->Lock );
|
|
MupDereferenceMasterQueryContext( masterContext );
|
|
|
|
//
|
|
// Return more processing required to the IO system so that it
|
|
// doesn't attempt further processing on the IRP we just freed.
|
|
//
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: MupFlushPrefixEntry
|
|
//
|
|
// Synopsis: Given a pathname, checks if the mup has the prefix cached.
|
|
// It removes the entry if it exists from the mup cache
|
|
//
|
|
// Arguments: [FileName] -- pathname which needs to be removed.
|
|
//
|
|
// Returns: TRUE if entry found in mup cache. False otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
BOOLEAN
|
|
MupFlushPrefixEntry(
|
|
PUNICODE_STRING pathName)
|
|
{
|
|
PUNICODE_PREFIX_TABLE_ENTRY entry;
|
|
PKNOWN_PREFIX knownPrefix;
|
|
|
|
ACQUIRE_LOCK( &MupPrefixTableLock );
|
|
|
|
entry = RtlFindUnicodePrefix( &MupPrefixTable, pathName, TRUE );
|
|
|
|
if (entry != NULL) {
|
|
knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
|
|
if ( knownPrefix->InTable ) {
|
|
MupRemoveKnownPrefixEntry( knownPrefix );
|
|
}
|
|
}
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
|
|
return (entry != NULL) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: MupInvalidatePrefixTable
|
|
//
|
|
// Synopsis: Removes all the entries from the mup prefix table.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
MupInvalidatePrefixTable(VOID)
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
PKNOWN_PREFIX knownPrefix;
|
|
|
|
ACQUIRE_LOCK( &MupPrefixTableLock );
|
|
|
|
listEntry = MupPrefixList.Flink;
|
|
while ( listEntry != &MupPrefixList ) {
|
|
knownPrefix = CONTAINING_RECORD( listEntry, KNOWN_PREFIX, ListEntry );
|
|
listEntry = listEntry->Flink;
|
|
if ( knownPrefix->InTable ) {
|
|
MupRemoveKnownPrefixEntry( knownPrefix );
|
|
}
|
|
}
|
|
|
|
RELEASE_LOCK( &MupPrefixTableLock );
|
|
}
|
|
|
|
VOID
|
|
MupRemoveKnownPrefixEntry(
|
|
PKNOWN_PREFIX knownPrefix
|
|
)
|
|
{
|
|
MUP_TRACE_LOW(KNOWN_PREFIX, MupRemoveKnownPrefixEntry,
|
|
LOGPTR(knownPrefix));
|
|
|
|
RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
|
|
RemoveEntryList(&knownPrefix->ListEntry);
|
|
knownPrefix->InTable = FALSE;
|
|
MupDereferenceKnownPrefix(knownPrefix);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IsThisASysVolPath(
|
|
IN PUNICODE_STRING PathName,
|
|
IN PUNICODE_STRING DCName)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether a given path is a domain-based path or not
|
|
The general algorithm is:
|
|
|
|
- Extract the first component of the path
|
|
- See if it the domain name
|
|
- If it is, and the 2nd component is SYSVOL or NETLOGON, return the DCName
|
|
|
|
Arguments
|
|
|
|
PathName - Name of entire file
|
|
DCName - If this is a domain-based path, this is the name of
|
|
a dc in the domain.
|
|
|
|
Returns value
|
|
|
|
STATUS_SUCCESS -- PathName is a domain-based path
|
|
STATUS_BAD_NETWORK_PATH -- PathName is not a domain-based path
|
|
|
|
--*/
|
|
NTSTATUS status;
|
|
PDFS_SPECIAL_ENTRY pSpecialEntry;
|
|
PUNICODE_STRING pName;
|
|
UNICODE_STRING RootName;
|
|
UNICODE_STRING ShareName;
|
|
USHORT i;
|
|
USHORT j;
|
|
PDFS_PKT Pkt;
|
|
BOOLEAN pktLocked;
|
|
|
|
DfsDbgTrace(+1, Dbg, "IsThisASysVolPath: PathName %wZ \n", PathName);
|
|
|
|
//
|
|
// Only proceed if the first character is a backslash.
|
|
//
|
|
|
|
if (PathName->Buffer[0] != UNICODE_PATH_SEP) {
|
|
DfsDbgTrace(-1, Dbg, "PathName does not begin with backslash\n", 0);
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
}
|
|
|
|
//
|
|
// Find the first component in the name.
|
|
//
|
|
|
|
for (i = 1;
|
|
i < PathName->Length/sizeof(WCHAR) &&
|
|
PathName->Buffer[i] != UNICODE_PATH_SEP;
|
|
i++) {
|
|
NOTHING;
|
|
}
|
|
|
|
if (PathName->Buffer[i] != UNICODE_PATH_SEP) {
|
|
DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
}
|
|
|
|
RootName.Length = (i-1) * sizeof(WCHAR);
|
|
RootName.MaximumLength = RootName.Length;
|
|
RootName.Buffer = &PathName->Buffer[1];
|
|
|
|
if (RootName.Length == 0)
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
|
|
//
|
|
// Figure out the share name
|
|
//
|
|
|
|
for (j = i+1;
|
|
j < PathName->Length/sizeof(WCHAR) &&
|
|
PathName->Buffer[j] != UNICODE_PATH_SEP;
|
|
j++) {
|
|
NOTHING;
|
|
}
|
|
|
|
ShareName.Length = (j - i - 1) * sizeof(WCHAR);
|
|
ShareName.MaximumLength = ShareName.Length;
|
|
ShareName.Buffer = &PathName->Buffer[i+1];
|
|
|
|
if (ShareName.Length == 0 || DfspIsSysVolShare(&ShareName) == FALSE)
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
|
|
Pkt = _GetPkt();
|
|
PktAcquireShared(TRUE, &pktLocked);
|
|
|
|
if (
|
|
(Pkt->DomainNameFlat.Buffer != NULL
|
|
&&
|
|
Pkt->DomainNameDns.Buffer != NULL
|
|
&&
|
|
Pkt->DCName.Buffer != NULL)
|
|
&&
|
|
(RtlCompareUnicodeString(&RootName, &Pkt->DomainNameFlat, TRUE) == 0
|
|
||
|
|
RtlCompareUnicodeString(&RootName, &Pkt->DomainNameDns, TRUE) == 0)
|
|
) {
|
|
pName = &Pkt->DCName;
|
|
DCName->Buffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
pName->MaximumLength,
|
|
' puM');
|
|
if (DCName->Buffer != NULL) {
|
|
DCName->Length = pName->Length;
|
|
DCName->MaximumLength = pName->MaximumLength;
|
|
RtlCopyMemory(
|
|
DCName->Buffer,
|
|
pName->Buffer,
|
|
pName->MaximumLength);
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
status = STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
PktRelease();
|
|
DfsDbgTrace(-1, Dbg, "IsThisASysVolPath: Exit -> %08lx\n", LongToPtr( status ) );
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MupDomainToDC(
|
|
PUNICODE_STRING RootName,
|
|
PUNICODE_STRING DCName)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine rewrites the file name of a domain-based path into a dc-based
|
|
path. Ex: \domainfoo\sysvol -> \dc1\sysvol
|
|
|
|
Arguments:
|
|
|
|
RootName - The RootName to rewrite
|
|
|
|
DCName - The name of the DC to change the path to
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status of the operation
|
|
|
|
--*/
|
|
ULONG Size;
|
|
PCHAR Buffer;
|
|
PWCHAR pBuf;
|
|
PWCHAR OrgBuffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
DfsDbgTrace(+1, Dbg, "MupDomainToDC: RootName = %wZ\n", RootName);
|
|
|
|
//
|
|
// Only proceed if the first character is a backslash.
|
|
//
|
|
|
|
if (RootName->Buffer == NULL) {
|
|
DfsDbgTrace(-1, Dbg, "RootName is NULL\n", 0);
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
}
|
|
|
|
if (RootName->Buffer[0] != UNICODE_PATH_SEP) {
|
|
DfsDbgTrace(-1, Dbg, "RootName does not begin with backslash\n", 0);
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
}
|
|
|
|
OrgBuffer = RootName->Buffer;
|
|
|
|
//
|
|
// Skip over leading UNICODE_PATH_SEP
|
|
//
|
|
|
|
RootName->Length -= sizeof(WCHAR);
|
|
RootName->MaximumLength -= sizeof(WCHAR);
|
|
RootName->Buffer++;
|
|
|
|
//
|
|
// Motor along until end of string or a UNICODE_PATH_SEP
|
|
//
|
|
|
|
while (RootName->Length > 0 && RootName->Buffer[0] != UNICODE_PATH_SEP) {
|
|
RootName->Length -= sizeof(WCHAR);
|
|
RootName->MaximumLength -= sizeof(WCHAR);
|
|
RootName->Buffer++;
|
|
}
|
|
|
|
if (RootName->Length == 0) {
|
|
DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
|
|
return( STATUS_BAD_NETWORK_PATH );
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate storage for the new file name.
|
|
//
|
|
|
|
Size = sizeof(WCHAR) + // leading UNICODE_PATH_SEP
|
|
DCName->Length +
|
|
RootName->Length;
|
|
|
|
Buffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
Size,
|
|
' puM');
|
|
|
|
if ( Buffer == NULL)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
//
|
|
// Leading UNICODE_PATH_SEP's
|
|
//
|
|
|
|
pBuf = (WCHAR *)Buffer;
|
|
*pBuf++ = UNICODE_PATH_SEP;
|
|
|
|
//
|
|
// Copy the DC name to the buffer
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
pBuf,
|
|
DCName->Buffer,
|
|
DCName->Length);
|
|
|
|
pBuf += DCName->Length / sizeof(WCHAR);
|
|
|
|
//
|
|
// Append the trailing file name
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
pBuf,
|
|
RootName->Buffer,
|
|
RootName->Length);
|
|
|
|
//
|
|
// Free the old file name string buffer.
|
|
//
|
|
|
|
ExFreePool( OrgBuffer );
|
|
|
|
RootName->Buffer = (PWCHAR)Buffer;
|
|
RootName->Length = (USHORT) Size;
|
|
RootName->MaximumLength = (USHORT) Size;
|
|
|
|
DfsDbgTrace(+1, Dbg, "MupDomainToDC: Exit\n", 0);
|
|
return STATUS_SUCCESS;
|
|
}
|