|
|
//+-------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: dnr.c
//
// Contents: Distributed name resolution process and control
//
// Functions: DnrStartNameResolution -- Start a name resolution
// DnrNameResolve -- Main loop for DNR
// DnrComposeFileName -- Canonicalize file name
// DnrCaptureCredentials -- Capture user-defined creds for Dnr
// DnrReleaseCredentials -- Dual of DnrCaptureCredentials
// DnrRedirectFileOpen -- Redirect a create IRP to some provider
// DnrPostProcessFileOpen -- Resume after return from redirect
// DnrGetAuthenticatedConnection -- Using Dnr credentials
// DnrReleaseAuthenticatedConnection -- returned by above func
// DfsBuildConnectionRequest -- Builds name of server IPC$ share
// DfsFreeConnectionRequest -- Free resources allocated above
// DfsCreateConnection -- Create a connection to a server IPC$
// DfsCloseConnection -- Close connection opened above
// DnrBuildReferralRequest -- Build Irp for referral request
// DnrInsertReferralAndResume -- Resume DNR after referral
// DnrCompleteReferral -- DPC to process a referral response
// DnrCompleteFileOpen -- DPC to process a file open completion
// DnrBuildFsControlRequest -- Create an IRP for an Fsctrl
// AllocateDnrContext -- Allocate a context record for DNR
// DeallocateDnrContext -- Free context record
// DnrConcatenateFilePath -- Construct path with backslashes etc
// DnrLocateDC -- Locate the server for a Dfs root
//
//--------------------------------------------------------------------------
#include "dfsprocs.h"
#include <smbtypes.h>
#include <smbtrans.h>
#include "fsctrl.h"
#include "fcbsup.h"
#include "dnr.h"
#include "creds.h"
#include "know.h"
#include "mupwml.h"
#include <netevent.h>
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_DNR)
//
// Local function prototypes
//
#define DNR_SET_TARGET_INFO(_DnrC, _Entry) \
if (((_DnrC)->pDfsTargetInfo == NULL) && (_Entry != NULL)) {\ (_DnrC)->pDfsTargetInfo = (_Entry)->pDfsTargetInfo; \ if ((_DnrC)->pDfsTargetInfo != NULL) { \ PktAcquireTargetInfo( (_DnrC)->pDfsTargetInfo); \ } \ }
PDNR_CONTEXT AllocateDnrContext( IN ULONG cbExtra );
#define DeallocateDnrContext(pNRC) ExFreePool(pNRC);
VOID DnrRebuildDnrContext( IN PDNR_CONTEXT DnrContext, IN PUNICODE_STRING NewDfsPrefix, IN PUNICODE_STRING RemainingPath);
VOID DnrCaptureCredentials( IN PDNR_CONTEXT DnrContext);
VOID DnrReleaseCredentials( IN PDNR_CONTEXT DnrContext);
NTSTATUS DnrGetAuthenticatedConnection( IN OUT PDNR_CONTEXT DnrContext);
VOID DnrReleaseAuthenticatedConnection( IN OUT PDNR_CONTEXT DnrContext);
NTSTATUS DfsBuildConnectionRequest( IN PDFS_SERVICE pService, IN PPROVIDER_DEF pProvider, OUT PUNICODE_STRING pShareName);
VOID DfsFreeConnectionRequest( IN OUT PUNICODE_STRING pShareName);
NTSTATUS DnrRedirectFileOpen ( IN PDNR_CONTEXT DnrContext );
NTSTATUS DnrPostProcessFileOpen( IN PDNR_CONTEXT DnrContext );
VOID DnrInsertReferralAndResume( IN PVOID Context);
VOID DnrLocateDC( IN PUNICODE_STRING FileName);
NTSTATUS DnrCompleteReferral( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PVOID Context );
NTSTATUS DnrCompleteFileOpen( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PVOID Context );
PIRP DnrBuildReferralRequest( IN PDNR_CONTEXT pDnrContext );
VOID PktFlushChildren( PDFS_PKT_ENTRY pEntry );
VOID MupInvalidatePrefixTable( VOID ); NTSTATUS DnrGetTargetInfo( PDNR_CONTEXT pDnrContext);
#define DFS_REFERENCE_OBJECT(d) \
ObReferenceObjectByPointer(d,0,NULL,KernelMode);
#define DFS_DEREFERENCE_OBJECT(d) \
ObDereferenceObject((PVOID)(d));
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DnrStartNameResolution )
#pragma alloc_text( PAGE, DnrNameResolve )
#pragma alloc_text( PAGE, DnrComposeFileName )
#pragma alloc_text( PAGE, DnrCaptureCredentials )
#pragma alloc_text( PAGE, DnrReleaseCredentials )
#pragma alloc_text( PAGE, DnrGetAuthenticatedConnection )
#pragma alloc_text( PAGE, DnrReleaseAuthenticatedConnection )
#pragma alloc_text( PAGE, DnrRedirectFileOpen )
#pragma alloc_text( PAGE, DnrPostProcessFileOpen )
#pragma alloc_text( PAGE, DfsBuildConnectionRequest )
#pragma alloc_text( PAGE, DfsFreeConnectionRequest )
#pragma alloc_text( PAGE, DnrBuildReferralRequest )
#pragma alloc_text( PAGE, DfsCreateConnection )
#pragma alloc_text( PAGE, DfsCloseConnection )
#pragma alloc_text( PAGE, DnrBuildFsControlRequest )
#pragma alloc_text( PAGE, DnrInsertReferralAndResume )
#pragma alloc_text( PAGE, DnrLocateDC )
#pragma alloc_text( PAGE, AllocateDnrContext )
#pragma alloc_text( PAGE, DnrRebuildDnrContext )
#pragma alloc_text( PAGE, DnrConcatenateFilePath )
#pragma alloc_text( PAGE, DfspGetOfflineEntry)
#pragma alloc_text( PAGE, DfspMarkServerOnline)
#pragma alloc_text( PAGE, DfspMarkServerOffline)
#pragma alloc_text( PAGE, DfspIsRootOnline)
//
// The following are not pageable since they can be called at DPC level
//
// DnrCompleteReferral
// DnrCompleteFileOpen
//
#endif
//+-------------------------------------------------------------------
//
// Function: DfsIsShareNull
//
// Synopsis: Is this name of the form "\server\"?
//
// Arguments: [FileName] - pointer to the UNICODE_STRING we are checking
//
// Returns: TRUE if FileName is "\server\", FALSE otherwise
//
//--------------------------------------------------------------------
BOOLEAN DfsIsShareNull(PUNICODE_STRING FileName) { USHORT RootEnd = 0; USHORT ShareEnd = 0; BOOLEAN result = FALSE; USHORT Length = 0;
// find the first '\'
// we start at 1 because the first character is also '\'
for (RootEnd = 1; RootEnd < FileName->Length/sizeof(WCHAR) && FileName->Buffer[RootEnd] != UNICODE_PATH_SEP; RootEnd++) {
NOTHING;
}
// now FileName->Buffer[RootEnd] == '\' and we are beyond the root part of the name
// find the end of the share part.
for (ShareEnd = RootEnd+1; ShareEnd < FileName->Length/sizeof(WCHAR) && FileName->Buffer[ShareEnd] != UNICODE_PATH_SEP; ShareEnd++) {
NOTHING;
}
// the length of the share name is ShareEnd - RootEnd - 1
// the -1 is becasue we have actually stepped one char beyond the
// share name's end
// For example: \root\share\link RootEnd=5, ShareEnd=11
// \root\share RootEnd=5, ShareEnd=11
// \root\ RootEnd=5, ShareEnd=6
Length = (USHORT) (ShareEnd - RootEnd - 1) * sizeof(WCHAR);
if(Length == 0) { result = TRUE; } else { result = FALSE; }
return result; }
NTSTATUS DfsRerouteOpenToMup( IN PFILE_OBJECT FileObject, IN PUNICODE_STRING FileName) {
UNICODE_STRING NewName; ULONG nameLength; NTSTATUS status;
nameLength = sizeof(DD_MUP_DEVICE_NAME ) + FileName->Length + sizeof(WCHAR); if (nameLength > MAXUSHORT) { status = STATUS_NAME_TOO_LONG; MUP_TRACE_HIGH(ERROR, DfsRerouteOpenToMup_Error_NameTooLong, LOGSTATUS(status) LOGPTR(FileObject)); return status; }
NewName.Buffer = ExAllocatePoolWithTag( PagedPool, nameLength, ' puM');
if ( NewName.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
NewName.MaximumLength = (USHORT)nameLength; NewName.Length = 0;
RtlAppendUnicodeToString(&NewName, DD_MUP_DEVICE_NAME); RtlAppendUnicodeStringToString(&NewName, FileName);
if (MupVerbose) { DbgPrint("Newname %wZ\n", &NewName); }
ExFreePool(FileObject->FileName.Buffer); FileObject->FileName = NewName;
return STATUS_REPARSE; }
// The name resolution process operates as a state machine in
// which the current step in the process is indicated by a state
// variable, and responses to requests from the network will
// transition the process to other states, from which actions
// are taken.
//
// When a user request needs further processing, an IRP is
// dispatched with a Completion Routine that will
// pick up processing when the sub-request is completed. The
// completion routine will adjust the name resolution state and restart the
// main loop of the state machine.
//
// The following state/action table describes the actions of
// the procedures which implement the state machine:
//
// Current Condition/ Next
// State Action State
// ------- ---------- -----
//
// Enter Acquire Pkt, canonicalize file LocalCompletion
// name, optimistic allocation of
// FCB fails/
// No action
//
// Enter Acquire Pkt, canonicalize file Start
// name, allocated FCB/
// Capture Credentials to use
//
// Start Got a referral, new pkt entry GetFirstReplica
// is already in DnrContext and
// pkt entry is not inter-dfs/
// Capture USN of pkt entry
//
// Start lookup in PKT returns match GetFirstReplica
// and pkt entry is not inter-dfs/
// Capture USN of pkt entry
//
// Start pkt entry from referral or Start
// lookup is inter-dfs/
// Change file name in DnrContext
// to name in new Dfs, rebuild
// DnrContext
//
// Start lookup in PKT, no match/ GetFirstDC
// No action
//
// GetFirstReplica Find First replica fails and Done
// we have already got a referral/
// Set final status to
// NO_SUCH_DEVICE (must be
// because we don't have an
// appropriate redirector)
//
// GetFirstReplica Find First replica fails and GetFirstDC
// we haven't yet got a referral/
// locate first DC to send
// referral request to.
//
// GetFirstReplica Replica found has no address, GetFirstDC
// means a domain-based Dfs with
// no DCs/
// No action
//
// GetFirstReplica Replica found with valid SendRequest
// address/
// Capture provider info under
// lock protection, Reference
// provider's device object,
//
// SendRequest Supplied credentials, and tree Done
// connect using creds fails/
// Set final status, dereference
// provider's device object
//
// SendRequest Allocate pool for new name/ PostProcessOpen
// Change file name into one that
// the provider can parse, pass
// the Create request to the
// provider, Derefence provider's
// device object when provider
// completes the request.
//
// SendRequest Pool Allocation fails/ Done
// Set final status, dereference
// provider's device object
//
// PostProcessOpen Underlying FS returned REPARSE, SendRequest
// successfully created or found a
// provider for the target redir/
// Capture provider information
// under lock protection,
// Reference providers Device obj.
//
// PostProcessOpen Underlying FS returned SUCCESS/ Done
// Insert optimistically allocated
// FCB into Fcb table, set final
// status
//
// PostProcessOpen Open failed with GetFirstDC
// PATH_NOT_COVERED or
// DFS_EXIT_POINT_FOUND, and
// we haven't yet gotten a
// referral/
// No action
//
// PostProcessOpen Open failed with Start
// OBJECT_TYPE_MISMATCH (ie,
// downlevel open found an
// interdfs link)/Change
// name in DnrContext to name
// in new Dfs, rebuild DnrContext
//
// PostProcessOpen Open failed with GetFirstReplica
// PATH_NOT_COVERED or
// DFS_EXIT_POINT_FOUND, and we
// already got a referral, and
// we have never reported an
// inconsistency/
// Report inconsistency
//
// PostProcessOpen Same as above, but we already GetNextReplica
// reported the inconsistency/
// Report the inconsistency
//
// PostProcessOpen Open failed with network error/ GetNextReplica
// No action
//
// PostProcessOpen Open failed with non-network Done
// error/
// Set final status
//
// GetNextReplica No more replicas and haven't GetFirstDC
// gotten a referral yet/
// no action
//
// GetNextReplica No more replicas and got a Done
// referral/
// no action
//
// GetNextReplica Replica found/ SendRequest
// Capture provider information
// under lock protection,
// Reference provider Device obj
//
// GetFirstDC Lookup referral entry not Done
// found or has no services, and
// we have already called DC
// Locator once/
// Set final status to
// CANT_ACCESS_DOMAIN_INFO
//
// GetFirstDC Lookup referral entry returned Done
// valid entry, but can't find a
// provider for it/
// Set final status to
// CANT_ACCESS_DOMAIN_INFO
//
// GetFirstDC Lookup referral entry returned GetReferrals
// valid entry, and found
// provider/
// Set DnrContext->pPktEntry to
// DC's entry, Capture provider
// info under lock protection,
// Reference provider's Device obj
//
// GetReferrals Unable to open DC's IPC$ share/ GetNextDC
// Dereference provider's device
// object
//
// GetReferrals Opened DC's IPC$ share, but Done
// unable to build referral
// request Irp/
// Dereference provider's device,
// Set final status to
// INSUFFICIENT_RESOURCES
//
// GetReferrals Opened DC's IPC$ share and CompleteReferral
// built referral request/
// Release Pkt, Send referral
// request
//
// GetNextDC Successfully found another GetReferrals
// DC/
// Capture provider info under
// lock protection, Reference
// provider's Device object
//
// GetNextDC Can't find another DC/ Done
// Set final status to
// CANT_ACCESS_DOMAIN_INFO
//
// Done Complete create Irp with
// DnrContext->FinalStatus
//
// LocalCompletion Complete create Irp with
// local status.
//
// CompleteReferral Referral returned with GetReferrals
// BUFFER_OVERFLOW/
// Set referral size to
// indicated amount
//
// CompleteReferral Referral returned, but Done
// error in creating entry/
// Dereference provider's
// device, set final status to
// result of creating entry
//
// CompleteReferral Referral returned and GetFirstDC
// successfully created entry,
// entry is inter-dfs/
// Dereference provider's device,
// Reset ReferralSize
//
// CompleteReferral Same as above, but entry Start
// is storage entry/
// Dereference provider's device,
// Adjust DnrContext->
// RemainingPart to correspond
// to the new entry
//
// CompleteReferral Referral request failed with GetNextDC
// some network error/
// Dereference Provider's device
//
// CompleteReferral Referral request failed with Done
// some non-network error/
// Dereference provider's Device,
// Set final status to this error
//
//+-------------------------------------------------------------------------
//
// Function: DnrStartNameResolution - Start a distributed name resolution
//
// Synopsis: DnrStartNameResolution starts the name resolution process
// for a request (typically an NtCreateFile).
//
// Effects: Could change the state of the PKT or individual
// PKT entries.
//
// Arguments: [IrpContext] - pointer to a IRP_CONTEXT structure for the
// current request.
// [Irp] - IRP being processed.
// [Vcb] - Vcb of logical root.
//
// Returns: NTSTATUS - Status to be returned to the I/O subsystem.
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS DnrStartNameResolution( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PDFS_VCB Vcb ) { PDNR_CONTEXT DnrContext; NTSTATUS Status; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; PUNICODE_STRING LogRootPrefix = &Vcb->LogRootPrefix; ULONG CreateOptions; USHORT cbFileName; SECURITY_QUALITY_OF_SERVICE sqos; ULONG cbFileNameLong;
MUP_TRACE_NORM(TRACE_IRP, DnrStartNameResolution_Entry, LOGPTR(Irp) LOGPTR(Vcb) LOGPTR(FileObject) LOGUSTR(FileObject->FileName) LOGUSTR(*LogRootPrefix));
cbFileNameLong = FileObject->FileName.Length + sizeof(UNICODE_PATH_SEP) + LogRootPrefix->Length + sizeof(UNICODE_NULL);
cbFileName = (USHORT)cbFileNameLong;
if( cbFileName != cbFileNameLong ) { //
// The resulting name is too long -- we cannot deal with it
//
Status = STATUS_OBJECT_NAME_INVALID; DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status)); MUP_TRACE_HIGH(ERROR, DnrStartNameResolution_Error_NameTooLong, LOGSTATUS(Status) LOGPTR(FileObject) LOGPTR(Irp)); return Status; }
//
// Allocate the DnrContext used to resolve the name. We optimize
// allocation by allocating room for the FileName at the end of the
// DnrContext.
//
DnrContext = AllocateDnrContext(cbFileName);
if (DnrContext == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status)); MUP_TRACE_HIGH(ERROR, DnrStartNameResolution_Error2, LOGSTATUS(Status) LOGPTR(FileObject) LOGPTR(Irp)); return Status; }
DnrContext->FileName.Length = 0; DnrContext->FileName.MaximumLength = cbFileName; DnrContext->FileName.Buffer = (PWCHAR) ( (PBYTE) DnrContext + sizeof(DNR_CONTEXT) );
//
// Since FileName.Buffer has not been separately allocated, we set this
// to FALSE.
//
DnrContext->NameAllocated = FALSE;
//
// Capture the user's security token so we can later impersonate if
// needed.
//
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); sqos.ImpersonationLevel = SecurityImpersonation; sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; sqos.EffectiveOnly = FALSE;
Status = SeCreateClientSecurity( Irp->Tail.Overlay.Thread, &sqos, FALSE, // Remote Session
&DnrContext->SecurityContext); // Return context.
MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrStartNameResolution_Error_SeCreateClientSecurity, LOGSTATUS(Status) LOGPTR(FileObject) LOGPTR(Irp) LOGUSTR(FileObject->FileName)); if (!NT_SUCCESS(Status)) { DeallocateDnrContext( DnrContext ); DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status)); return( Status ); }
DnrContext->Impersonate = FALSE;
ASSERT(NT_SUCCESS(Status));
//
// Initialize the rest of the DnrContext
//
DnrContext->AuthConn = NULL; DnrContext->OriginalIrp = Irp; DnrContext->pIrpContext = IrpContext; DnrContext->Credentials = NULL; DnrContext->FinalStatus = STATUS_SUCCESS; DnrContext->FcbToUse = NULL; DnrContext->Vcb = Vcb; DnrContext->State = DnrStateEnter; DnrContext->Attempts = 0; DnrContext->DnrActive = FALSE; DnrContext->ReleasePkt = FALSE; DnrContext->GotReferral = FALSE; DnrContext->FoundInconsistency = FALSE; DnrContext->CalledDCLocator = FALSE; DnrContext->CachedConnFile = FALSE; DnrContext->ReferralSize = MAX_REFERRAL_LENGTH; KeQuerySystemTime(&DnrContext->StartTime);
CreateOptions = IrpSp->Parameters.Create.Options;
//
// ... and resolve the name
//
return DnrNameResolve(DnrContext); }
//+-------------------------------------------------------------------------
//
// Function: DnrNameResolve - Main loop for DNR
//
// Synopsis: DnrNameResolve drives the name resolution process
// for a request (typically an NtCreateFile).
//
// Effects: Could change the state of the PKT or individual
// PKT entries.
//
// Arguments: [DnrContext] - pointer to a DNR_CONTEXT structure which
// records the state of the DNR.
//
// Returns: NTSTATUS - Status to be returned to the I/O subsystem.
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS DnrNameResolve( IN PDNR_CONTEXT DnrContext ) { PIO_STACK_LOCATION IrpSp; NTSTATUS Status = STATUS_SUCCESS; PDFS_VCB Vcb; PIRP Irp; BOOLEAN LastEntry; PDFS_PKT_ENTRY shortPfxMatch; UNICODE_STRING shortRemainingPart; LARGE_INTEGER EndTime; PFILE_OBJECT InputFileObject;
DfsDbgTrace(+1, Dbg, "DnrNameResolve: Entered\n", 0);
ASSERT( !DnrContext->DnrActive && "Recursive call to Dnr!\n");
DnrContext->DnrActive = TRUE;
//
// If we need to impersonate the original caller, do so before doing
// anything else.
//
Irp = DnrContext->OriginalIrp; IrpSp = IoGetCurrentIrpStackLocation(Irp); InputFileObject = IrpSp->FileObject; Vcb = DnrContext->Vcb;
if (DnrContext->Impersonate) {
Status = SeImpersonateClientEx( &DnrContext->SecurityContext, (PETHREAD) NULL); MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_SeImpersonateClientEx, LOGSTATUS(Status) LOGPTR(InputFileObject));
if (!NT_SUCCESS(Status)) {
DnrContext->DnrActive = FALSE; DnrContext->State = DnrStateLocalCompletion; DfsDbgTrace(0, Dbg, "DnrNameResolve quitting due to SeImpersonateClientEx returning 0x%x\n", ULongToPtr(Status));
}
}
//
// Drive the name resolution process as far as possible before
// it is necessary to wait for an I/O completion.
//
while (1) { PDFS_PKT_ENTRY pktEntry = NULL; PFILE_OBJECT FileObject = IrpSp->FileObject;
if (DnrContext->State == DnrStateGetFirstReplica || DnrContext->State == DnrStateGetFirstDC) { if (++DnrContext->Attempts > MAX_DNR_ATTEMPTS) { Status = STATUS_BAD_NETWORK_PATH; DnrContext->State = DnrStateLocalCompletion; DfsDbgTrace(0, 0, "DFS: DnrNameResolve quitting due to MAX_DNR_ATTEMPTS %d\n", UIntToPtr(DnrContext->Attempts)); } }
if (DnrContext->State == DnrStateStart) { if (DnrContext->Attempts > MAX_DNR_ATTEMPTS) { Status = STATUS_BAD_NETWORK_PATH; DnrContext->State = DnrStateLocalCompletion; } }
MUP_TRACE_LOW(DNR, DnrNameResolve_TopOfLoop, LOGUSTR(FileObject->FileName) LOGULONG(DnrContext->State) ); switch (DnrContext->State) {
case DnrStateEnter: #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateEnter\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ASSERT(DnrContext->ReleasePkt == FALSE);
PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
//
// We need to construct the fully qualified file name given the
// logical root and the input file name relative to that root.
// DnrComposeFileName will allocate memory to hold a string that
// is the concatenation of the name of the logical root wrt org
// and the file name.
//
//
ASSERT((FileObject->FileName.Length & 0x1) == 0);
DnrComposeFileName( &DnrContext->FileName, DnrContext->Vcb, FileObject->RelatedFileObject, &FileObject->FileName);
DnrContext->ContextFileName = DnrContext->FileName;
DfsDbgTrace(0, Dbg, "DnrComposeFileName -> %wZ\n", &FileObject->FileName);
if(DfsIsShareNull(&DnrContext->FileName)) { //
// It doesn't make sense for us to have a name in the form
// "\server\" or "\domain\" so we reject it. If we didn't reject these
// names we would wind up bugchecking when processing the
// referral with a NULL sharename.
//
Status = STATUS_INVALID_PARAMETER; DnrContext->State = DnrStateLocalCompletion; break; }
Status = DfspIsRootOnline(&DnrContext->FileName, (BOOLEAN) ((DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0)); if (!NT_SUCCESS(Status)) { DnrContext->State = DnrStateLocalCompletion; break; } #if DBG
if (MupVerbose) DbgPrint(" DnrContext->FileName=(%wZ)\n", &DnrContext->FileName); #endif
//
// Allocate an FCB now for use if the DNR succeeds. We must, do
// this, or we won't know how what to do if the underlying FS
// opens the file and then we are unable to allocate the FCB.
//
ASSERT(DnrContext->FcbToUse == NULL);
DnrContext->FcbToUse = DfsCreateFcb( NULL, DnrContext->Vcb, &DnrContext->ContextFileName);
if (DnrContext->FcbToUse == NULL) { DfsDbgTrace(0, Dbg, "Could not create FCB!\n", 0); Status = STATUS_INSUFFICIENT_RESOURCES; DnrContext->State = DnrStateLocalCompletion; break; }
DnrContext->FcbToUse->FileObject = FileObject; DfsSetFileObject(FileObject, RedirectedFileOpen, DnrContext->FcbToUse);
DnrCaptureCredentials(DnrContext);
DnrContext->State = DnrStateStart;
//
// Fall through
//
case DnrStateStart: DfsDbgTrace(0, Dbg, "FSM state Start\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateStart\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); DbgPrint(" DnrContext->FileName=(%wZ)\n", &DnrContext->FileName); } #endif
ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
//
// Try to match the filename with the best
// PktEntry we have.
//
//
// Do the match in the full prefix table
//
pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt, &DnrContext->FileName, &DnrContext->RemainingPart);
//
// Then do a match in the short prefix table
//
shortPfxMatch = PktLookupEntryByShortPrefix( &DfsData.Pkt, &DnrContext->FileName, &shortRemainingPart);
if (shortPfxMatch != NULL) {
if (pktEntry == NULL) {
pktEntry = shortPfxMatch;
DnrContext->RemainingPart = shortRemainingPart;
} else if (shortPfxMatch->Id.Prefix.Length > pktEntry->Id.Prefix.Length) {
pktEntry = shortPfxMatch;
DnrContext->RemainingPart = shortRemainingPart;
}
}
//
// If the entry found is stale and this is our first attempt at dnr,
// force another referral request.
//
if (DnrContext->Attempts == 0 && pktEntry != NULL && pktEntry->ExpireTime <= 0) { #if DBG
if (MupVerbose) DbgPrint(" pktEntry [%wZ] is stale - force getting another\n", &pktEntry->Id.Prefix); #endif
DnrContext->pPktEntry = pktEntry;
DnrContext->State = DnrStateGetFirstDC; //
// Now break out so we restart Dnr and get a referral
//
break;
}
#if 0
if (pktEntry == NULL) {
PUNICODE_STRING filePath = &DnrContext->FileName; UNICODE_STRING dfsRootName; UNICODE_STRING shareName; NTSTATUS status; PDFS_SPECIAL_ENTRY pSpecialEntry; ULONG i, j;
for (i = 1; i < filePath->Length/sizeof(WCHAR) && filePath->Buffer[i] != UNICODE_PATH_SEP; i++) {
NOTHING;
}
dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR)); dfsRootName.MaximumLength = dfsRootName.Length; dfsRootName.Buffer = &filePath->Buffer[1];
for (j = i+1; j < filePath->Length/sizeof(WCHAR) && filePath->Buffer[j] != UNICODE_PATH_SEP; j++) {
NOTHING;
}
shareName.Length = (USHORT) (j - i - 1) * sizeof(WCHAR); shareName.MaximumLength = shareName.Length; shareName.Buffer = &filePath->Buffer[i+1];
PktRelease(); DnrContext->ReleasePkt = FALSE;
status = PktExpandSpecialName( &dfsRootName, &pSpecialEntry);
PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
if (NT_SUCCESS(status)) {
ULONG Len;
if ((j+1) < filePath->Length/sizeof(WCHAR)) {
Len = filePath->Length - ((j+1) * sizeof(WCHAR));
DnrContext->RemainingPart.Buffer = &filePath->Buffer[j+1]; DnrContext->RemainingPart.Length = (USHORT) Len; DnrContext->RemainingPart.MaximumLength = (USHORT) Len;
} else {
DnrContext->RemainingPart.Buffer = NULL; DnrContext->RemainingPart.Length = 0; DnrContext->RemainingPart.MaximumLength = 0;
}
status = PktEntryFromSpecialEntry( pSpecialEntry, &shareName, &pktEntry);
InterlockedDecrement(&pSpecialEntry->UseCount);
}
} #endif
#if 0
if (pktEntry != NULL) {
pktEntry->ExpireTime = pktEntry->TimeToLive;
} #endif
DfsDbgTrace(0, Dbg, "DnrNameResolve: found pktEntry %08lx\n", pktEntry);
DNR_SET_TARGET_INFO( DnrContext, pktEntry );
if (pktEntry == NULL) {
//
// We didn't find any entry. We set pPktEntry to NULL so that
// in GetFirstDC, the call to PktLookupReferralEntry will
// return the right thing (ie, will give use the highest DC we
// know about).
//
DnrContext->pPktEntry = NULL; DnrContext->State = DnrStateGetFirstDC;
} else if (pktEntry->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) {
DnrRebuildDnrContext( DnrContext, &pktEntry->Info.ServiceList[0].Address, &DnrContext->RemainingPart);
//
// The DnrContext has been rebuilt and programmed to
// "restart" DNR. So, we'll just break out of the state
// machine and reenter it with the reconstructed context
//
} else {
ASSERT(pktEntry != NULL);
DnrContext->pPktEntry = pktEntry; DnrContext->USN = pktEntry->USN; DnrContext->State = DnrStateGetFirstReplica;
} break;
case DnrStateGetFirstReplica: DfsDbgTrace(0, Dbg, "FSM state GetFirstReplica\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateGetFirstReplica\n", (EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)); } #endif
ASSERT(DnrContext->ReleasePkt == TRUE);
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
Status = ReplFindFirstProvider(DnrContext->pPktEntry, NULL, NULL, &DnrContext->pService, &DnrContext->RSelectContext, &LastEntry);
if (! NT_SUCCESS(Status)) {
ULONG PktType = DnrContext->pPktEntry->Type;
ExReleaseResourceLite(&DfsData.Resource);
DfsDbgTrace(0, Dbg, "No provider found %08lx\n", ULongToPtr(Status));
if (DnrContext->GotReferral || (PktType & PKT_ENTRY_TYPE_SYSVOL) != 0 || DnrContext->GotReparse == TRUE ) { DnrContext->FinalStatus = STATUS_NO_SUCH_DEVICE; DnrContext->State = DnrStateDone; break; } else { DnrContext->State = DnrStateGetFirstDC; break; }
} else if (DnrContext->pService->Address.Length == 0) {
ExReleaseResourceLite(&DfsData.Resource);
DfsDbgTrace(0, Dbg, "Service with no address, going for referral\n", 0);
DnrContext->State = DnrStateGetFirstDC; break;
} else {
ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pService->pProvider != NULL);
#if DBG
if (MupVerbose) DbgPrint(" Alternate Name=[%wZ] Address=[%wZ]\n", &DnrContext->pService->Name, &DnrContext->pService->Address); #endif
DnrContext->pProvider = DnrContext->pService->pProvider; DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
if (LastEntry == TRUE) { DnrContext->DfsNameContext.Flags |= DFS_FLAG_LAST_ALTERNATE; } else { DnrContext->DfsNameContext.Flags &= ~DFS_FLAG_LAST_ALTERNATE; }
ExReleaseResourceLite(&DfsData.Resource);
DnrContext->State = DnrStateSendRequest; } // FALL THROUGH ...
case DnrStateSendRequest: #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateSendRequest\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
DfsDbgTrace(0, Dbg, "FSM state SendRequest\n", 0);
ASSERT(DnrContext->ReleasePkt == TRUE);
ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pProvider != NULL); ASSERT(DnrContext->TargetDevice != NULL);
//
// First of all, check to see if the volume is offline
//
if (DnrContext->pService->Type & DFS_SERVICE_TYPE_OFFLINE) {
DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); DnrContext->FinalStatus = STATUS_DEVICE_OFF_LINE; DnrContext->State = DnrStateDone; DfsDbgTrace(-1, Dbg, "DnrNameResolve: Device Offline\n",0); Status = STATUS_DEVICE_OFF_LINE; MUP_TRACE_HIGH(ERROR, DnrNameResolve_Error3, LOGSTATUS(Status) LOGPTR(FileObject)); break; }
//
// Next, try to make an authenticated connection to the server, if needed
//
// The pkt lock may be dropped in this call, so keep the pkt entry from going
// away.
//
InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
PktRelease(); DnrContext->ReleasePkt = FALSE;
Status = DnrGetAuthenticatedConnection( DnrContext );
PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
if (!NT_SUCCESS(Status)) {
DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); DnrContext->FinalStatus = Status;
//
// If the error is such that we need to try another replica,
// do so here.
//
if (ReplIsRecoverableError(Status)) { DnrContext->State = DnrStateGetNextReplica; } else { DnrContext->State = DnrStateDone; }
DfsDbgTrace(-1, Dbg, "DnrNameResolve: Unable to get connection %08lx\n", ULongToPtr(Status));
break; }
if (DnrContext->USN != DnrContext->pPktEntry->USN) {
//
// Dang, Pkt Entry changed when we made the
// connection. We'll have to retry.
//
DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); DnrReleaseAuthenticatedConnection(DnrContext); DnrContext->State = DnrStateStart; DfsDbgTrace(-1, Dbg, "DnrNameResolve: USN delta - restarting DNR\n", 0); break;
}
Status = DnrRedirectFileOpen(DnrContext);
if (Status == STATUS_PENDING) { return(Status); } break;
case DnrStatePostProcessOpen: DfsDbgTrace(0, Dbg, "FSM state PostProcessOpen\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStatePostProcessOpen\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
//
// We come to this state only after sending an open request over
// the net. We should never hold the Pkt while going over the net.
// Hence the sense of the assert below.
//
ASSERT(DnrContext->ReleasePkt == FALSE);
Status = DnrPostProcessFileOpen(DnrContext); pktEntry = DnrContext->pPktEntry; break;
case DnrStateGetNextReplica: DfsDbgTrace(0, Dbg, "FSM state GetNextReplica\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrGetNextReplica\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ASSERT(DnrContext->ReleasePkt == TRUE);
{ NTSTATUS ReplStatus;
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
ReplStatus = ReplFindNextProvider(DnrContext->pPktEntry, &DnrContext->pService, &DnrContext->RSelectContext, &LastEntry);
if (ReplStatus == STATUS_NO_MORE_ENTRIES) {
ULONG PktType = DnrContext->pPktEntry->Type;
#if DBG
if (MupVerbose) DbgPrint(" No more alternates...\n"); #endif
//
// If all failed and we are about to give up due to one
// of two reasons :
// 1. None of the Services for the PkEntry being used
// responded (either they are down or network down!).
// 2. Some or all of the Services have inconsistencies
// which we detected and informed the DC about along
// the way.
// If we did land up with case 2 then we really have to
// try and get a new referral and use that - just in
// case things have changed since then at the DC. So let
// us get into a GetReferral State and try once again.
//
ExReleaseResourceLite( &DfsData.Resource );
if (DnrContext->GotReferral || (PktType & PKT_ENTRY_TYPE_SYSVOL) != 0 || DnrContext->GotReparse == TRUE ) { DnrContext->State = DnrStateDone; } else { DnrContext->State = DnrStateGetFirstDC; }
} else if (NT_SUCCESS( ReplStatus )) {
//
// Found another replica, go back and retry.
//
ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pService->pProvider != NULL);
DnrContext->pProvider = DnrContext->pService->pProvider; DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
ExReleaseResourceLite(&DfsData.Resource);
DnrContext->State = DnrStateSendRequest;
#if DBG
if (MupVerbose) DbgPrint(" Alternate Name=[%wZ] Address=[%wZ]\n", &DnrContext->pService->Name, &DnrContext->pService->Address); #endif
if (LastEntry == TRUE) { DnrContext->DfsNameContext.Flags |= DFS_FLAG_LAST_ALTERNATE; } else { DnrContext->DfsNameContext.Flags &= ~DFS_FLAG_LAST_ALTERNATE; }
break; } else {
ExReleaseResourceLite(&DfsData.Resource);
ASSERT(ReplStatus == STATUS_NO_MORE_ENTRIES); } } break;
case DnrStateGetFirstDC: DfsDbgTrace(0, Dbg, "FSM state GetFirstDC\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateGetFirstDC\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ASSERT(DnrContext->ReleasePkt == TRUE);
{ NTSTATUS ReplStatus; PDFS_PKT_ENTRY pPktEntryDC = NULL;
pPktEntryDC = PktLookupReferralEntry(&DfsData.Pkt, DnrContext->pPktEntry);
//
// If there is no root entry, or it is stale, or it has no
// services, then try for a new referral entry for the root
//
if ( pPktEntryDC == NULL || pPktEntryDC->ExpireTime <= 0 || pPktEntryDC->Info.ServiceCount == 0 ) {
if (DnrContext->CalledDCLocator) { DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO; DnrContext->State = DnrStateDone; break; }
//
// We are unable to find a DC to go to for referrals.
// This can only happen if we don't have the pkt entry
// for the root of the Dfs. Try to get the root entry.
//
DfsDbgTrace(0, Dbg, "No DC info - will try locator\n", 0); #if DBG
if (MupVerbose) { if (pPktEntryDC != NULL && pPktEntryDC <= 0) DbgPrint(" Entry is stale.\n"); DbgPrint(" No Root/DC info - will try locator\n"); } #endif
PktRelease(); DnrContext->ReleasePkt = FALSE;
DnrLocateDC(&DnrContext->FileName);
PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
DnrContext->CalledDCLocator = TRUE; DnrContext->State = DnrStateStart;
break;
}
#if DBG
if (MupVerbose) { if (DnrContext->pPktEntry != NULL) DbgPrint(" DnrContext->pPktEntry=[%wZ]\n", &DnrContext->pPktEntry->Id.Prefix); else DbgPrint(" DnrContext->pPktEntry=NULL\n"); DbgPrint(" pPktEntryDC=[%wZ]\n", &pPktEntryDC->Id.Prefix); } #endif
DnrContext->pPktEntry = pPktEntryDC;
DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry ); DnrContext->USN = pPktEntryDC->USN;
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
ReplStatus = ReplFindFirstProvider(pPktEntryDC, NULL, NULL, &DnrContext->pService, &DnrContext->RDCSelectContext, &LastEntry);
if (!NT_SUCCESS(ReplStatus)) { ExReleaseResourceLite(&DfsData.Resource); DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO; DnrContext->State = DnrStateDone; break; } else { ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pService->pProvider != NULL);
InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
DnrContext->pProvider = DnrContext->pService->pProvider; DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
ExReleaseResourceLite(&DfsData.Resource);
} } DnrContext->State = DnrStateGetReferrals; /* FALL THROUGH */
case DnrStateGetReferrals: DfsDbgTrace(0, Dbg, "FSM state GetReferrals\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateGetReferrals\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ASSERT(DnrContext->ReleasePkt == TRUE);
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
//
// Attempt to open the Dfs Root's IPC$ share if we haven't already done
// so.
//
if (DnrContext->pService->ConnFile == NULL) { HANDLE hDC; SE_IMPERSONATION_STATE DisabledImpersonationState; BOOLEAN RestoreImpersonationState = FALSE;
ExReleaseResourceLite(&DfsData.Resource); KeQuerySystemTime(&EndTime);
#if DBG
if (MupVerbose) DbgPrint(" [%d] Opening connection to [\\%wZ\\IPC$] using [%wZ]\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), &DnrContext->pService->Name, &DnrContext->pProvider->DeviceName); #endif
if (MupUseNullSessionForDfs) { RestoreImpersonationState = PsDisableImpersonation( PsGetCurrentThread(), &DisabledImpersonationState); } Status = DfsCreateConnection( DnrContext->pService, DnrContext->pProvider, (BOOLEAN) ((DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0), &hDC);
if (RestoreImpersonationState) { PsRestoreImpersonation( PsGetCurrentThread(), &DisabledImpersonationState); }
#if DBG
if (MupVerbose) DbgPrint(" Open of connection Status=0x%x\n", Status); #endif
if (NT_SUCCESS( Status )) {
if (DnrContext->USN != DnrContext->pPktEntry->USN) {
//
// Dang, Pkt Entry changed when we made the
// connection. We'll have to retry.
//
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
ZwClose( hDC );
DnrContext->State = DnrStateGetFirstDC; #if DBG
if (MupVerbose) DbgPrint(" USN changed.\n"); #endif
break;
}
}
if ( NT_SUCCESS( Status ) ) {
PFILE_OBJECT DcFileObject; // Need stack based variable
// because ObRef... expects
// this parameter to be in
// non-paged memory.
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
if (DnrContext->pService->ConnFile == NULL) {
//
// 426184, need to check return code for errors.
//
Status = ObReferenceObjectByHandle( hDC, 0, NULL, KernelMode, (PVOID *)&DcFileObject, NULL); MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_ObReferenceObjectByHandle, LOGSTATUS(Status) LOGPTR(DcFileObject)); #if DBG
if (MupVerbose) DbgPrint(" ObReferenceObjectByHandle returned 0x%x\n", Status); #endif
if ( NT_SUCCESS( Status ) ) { DnrContext->pService->ConnFile = DcFileObject; } ZwClose( hDC ); } }
if ( NT_SUCCESS( Status ) ) { DnrContext->DCConnFile = DnrContext->pService->ConnFile; DnrContext->CachedConnFile = FALSE; DFS_REFERENCE_OBJECT( DnrContext->DCConnFile );
ExReleaseResourceLite( &DfsData.Resource );
} else if (DfsEventLog > 0) {
LogWriteMessage( DFS_CONNECTION_FAILURE, Status, 1, &DnrContext->pService->Name);
}
} else {
//
// DnrContext->pService is protected by the Pkt lock. Since we
// will be using pService->ConnFile to send the referral request,
// we better reference and cache it.
//
DnrContext->DCConnFile = DnrContext->pService->ConnFile; DFS_REFERENCE_OBJECT( DnrContext->DCConnFile ); DnrContext->CachedConnFile = TRUE; ExReleaseResourceLite(&DfsData.Resource); Status = STATUS_SUCCESS;
}
//
// Unable to get IPC$ share, try the next Dfs root
//
if (!NT_SUCCESS(Status)) { DnrContext->State = DnrStateGetNextDC; DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); break; }
//
// Opened Dfs Root's IPC$ share - remember this DC is a good one.
//
ReplSetActiveService( DnrContext->pPktEntry, DnrContext->RDCSelectContext);
//
// Build the Referral request...
//
Irp = DnrBuildReferralRequest(DnrContext);
if (Irp == NULL) { InterlockedDecrement(&DnrContext->pPktEntry->UseCount); Irp = DnrContext->OriginalIrp; DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); DFS_DEREFERENCE_OBJECT(DnrContext->DCConnFile); DnrContext->State = DnrStateDone; #if DBG
if (MupVerbose) DbgPrint(" DnrBuildReferralRequest returned NULL irp\n"); #endif
break; }
DnrContext->State = DnrStateCompleteReferral;
PktRelease(); DnrContext->ReleasePkt = FALSE;
//
// The PktReferralRequests semaphore is used to control how
// many threads can simultaneously be going for referrals. The
// following Wait will decrement the PktReferralRequests
// semaphore by 1 if it is not already 0. If it is 0, then
// this thread will suspend until someone else bumps up the
// semaphore by 1. We will bump up the semaphore count in
// DnrCompleteReferral.
//
Status = KeWaitForSingleObject( &DfsData.PktReferralRequests, UserRequest, // WaitReason - don't care
KernelMode, FALSE, // Alertable
NULL); // Timeout
ASSERT(Status == STATUS_SUCCESS);
KeQuerySystemTime(&EndTime); #if DBG
if (MupVerbose) DbgPrint(" [%d] asking for referral (IoCallDriver)\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); #endif
IoMarkIrpPending( DnrContext->OriginalIrp );
Status = IoCallDriver( DnrContext->TargetDevice, Irp );
MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_IoCallDriver, LOGSTATUS(Status) LOGPTR(FileObject)); //
// We now return STATUS_PENDING. DnrCompleteReferral will
// resume the Dnr.
//
DfsDbgTrace(-1, Dbg, "DnrNameResolve: returning %08lx\n", ULongToPtr(STATUS_PENDING));
return(STATUS_PENDING);
case DnrStateGetNextDC: DfsDbgTrace(0, Dbg, "FSM State GetNextDC\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateGetNextDC\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
{ NTSTATUS ReplStatus; PDFS_PKT_ENTRY pPktEntry = NULL; UNICODE_STRING RemPath;
pPktEntry = PktLookupEntryByPrefix(&DfsData.Pkt, &DnrContext->FileName, &RemPath);
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
ReplStatus = ReplFindNextProvider(DnrContext->pPktEntry, &DnrContext->pService, &DnrContext->RDCSelectContext, &LastEntry); if (NT_SUCCESS(ReplStatus)) { ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pService->pProvider != NULL);
DnrContext->pProvider = DnrContext->pService->pProvider; DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
DnrContext->State = DnrStateGetReferrals; } else if (pPktEntry != NULL && pPktEntry->ExpireTime <= 0) { ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() ); #if DBG
if (MupVerbose) { DbgPrint(" Out of roots to try for referral for [%wZ]\n", &DnrContext->FileName); DbgPrint(" Found stale referral [%wZ], adding 60 sec to it\n", &pPktEntry->Id.Prefix); } #endif
InterlockedDecrement(&DnrContext->pPktEntry->UseCount); DnrContext->State = DnrStateStart; } else { #if DBG
if (MupVerbose) DbgPrint(" Out of roots to try for referral for [%wZ], no stale found\n", &DnrContext->FileName); #endif
InterlockedDecrement(&DnrContext->pPktEntry->UseCount); DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO; DnrContext->State = DnrStateDone; }
ExReleaseResourceLite(&DfsData.Resource);
} break;
case DnrStateDone: #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateDone\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
Status = DnrContext->FinalStatus; // FALL THROUGH ...
case DnrStateLocalCompletion: DfsDbgTrace(0, Dbg, "FSM state Done\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] FSM state DnrStateLocalCompletion\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
if (Status != STATUS_LOGON_FAILURE && !ReplIsRecoverableError(Status)) {
if (DnrContext->pPktEntry != NULL && (DnrContext->pPktEntry->Type & PKT_ENTRY_TYPE_SYSVOL) && (DnrContext->pPktEntry->Link.Flink == &(DnrContext->pPktEntry->Link))) {
PDFS_PKT Pkt = _GetPkt(); PDFS_PKT_ENTRY Entry = DnrContext->pPktEntry; PDFS_PKT_ENTRY pMatchEntry;
InterlockedIncrement(&Entry->UseCount);
if (DnrContext->ReleasePkt) PktRelease();
PktAcquireExclusive(TRUE, &DnrContext->ReleasePkt);
InterlockedDecrement(&Entry->UseCount);
#if DBG
if ((MupVerbose) && (pktEntry != NULL)) { //
// Temporary debug stuff.
//
if ((pktEntry->NodeTypeCode != DSFS_NTC_PKT_ENTRY) || (pktEntry->NodeByteSize != sizeof(*pktEntry))) { DbgPrint("DnrNameResolve: Updating bogus Pkt entry avoided: Pkt Entry 0x%x\n", pktEntry); } } #endif
pMatchEntry = PktFindEntryByPrefix( Pkt, &Entry->Id.Prefix);
if ((Entry->Type & PKT_ENTRY_TYPE_DELETE_PENDING) == 0) { if (pMatchEntry == NULL) { if (DfsInsertUnicodePrefix(&Pkt->PrefixTable, &Entry->Id.Prefix, &Entry->PrefixTableEntry)) {
//
// We successfully created the prefix entry, so now we link
// this entry into the PKT.
//
PktLinkEntry(Pkt, Entry); } } else { //
// Destroy this entry if it isn't in the table, as we are
// about to orphan it.
//
if (pMatchEntry != NULL && pMatchEntry != Entry) {
Entry->ActiveService = NULL; PktEntryIdDestroy(&Entry->Id, FALSE); PktEntryInfoDestroy(&Entry->Info, FALSE); ExFreePool(Entry); } } } PktRelease(); DnrContext->ReleasePkt = FALSE;
}
}
if (DnrContext->ReleasePkt) PktRelease();
if ((Status == STATUS_DEVICE_OFF_LINE) && (IrpSp->FileObject->RelatedFileObject == NULL)) { Status = DfsRerouteOpenToMup(IrpSp->FileObject, &DnrContext->FileName); }
if (DnrContext->FcbToUse != NULL) { DfsDetachFcb(DnrContext->FcbToUse->FileObject, DnrContext->FcbToUse); ExFreePool( DnrContext->FcbToUse ); }
DfsCompleteRequest(DnrContext->pIrpContext, Irp, Status);
DnrReleaseCredentials(DnrContext);
SeDeleteClientSecurity( &DnrContext->SecurityContext );
if (DnrContext->NameAllocated) ExFreePool( DnrContext->FileName.Buffer );
if (DnrContext->pDfsTargetInfo != NULL) { PktReleaseTargetInfo(DnrContext->pDfsTargetInfo); DnrContext->pDfsTargetInfo = NULL; } KeQuerySystemTime(&EndTime); #if DBG
if (MupVerbose) DbgPrint("[%d] DnrNameResolve exit 0x%x\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), Status); #endif
DeallocateDnrContext(DnrContext);
DfsDbgTrace(-1, Dbg, "DnrNameResolve: Exit ->%x\n", ULongToPtr(Status)); return Status;
default: BugCheck("DnrNameResolve: unexpected DNR state"); } }
BugCheck("DnrNameResolve: unexpected exit from loop"); }
//+----------------------------------------------------------------------------
//
// Function: DnrComposeFileName
//
// Synopsis: Given a DFS_VCB (implicitly a Device Object), and a file name
// relative to that device, this routine will compose a fully
// qualified name (ie, a name relative to the highest (org) root).
//
// Arguments: [FullName] -- Fully qualified name destination.
// [Vcb] -- Pointer to Vcb of Device Object.
// [RelatedFile] -- Related file object.
// [FileName] -- The file being "name resolved"
//
// Returns:
//
// Note: This function assumes that file names are composed precisely
// of two parts - the name relative to org of the file object's
// device, followed by the name of the file relative to the device
// This may not be true if we have a related file object! In that
// case, the full name is three part - device name relative to
// org, related file name relative to device, and file name
// relative to related file. However, in create.c,
// DfsCommonCreate, we manipulate file objects so all opens look
// like "non-relative" opens. If one changes that code, then
// this function must be changed to correspond.
//
//-----------------------------------------------------------------------------
VOID DnrComposeFileName( OUT PUNICODE_STRING FullName, IN PDFS_VCB Vcb, IN PFILE_OBJECT RelatedFile, IN PUNICODE_STRING FileName ) { PUNICODE_STRING LogRootPrefix = &(Vcb->LogRootPrefix);
ASSERT(FullName->MaximumLength >= FileName->Length + LogRootPrefix->Length); ASSERT(FullName->Length == 0); ASSERT(FullName->Buffer != NULL);
if ((LogRootPrefix->Length > 0) && (RelatedFile == NULL)) { RtlMoveMemory(FullName->Buffer, LogRootPrefix->Buffer, LogRootPrefix->Length); FullName->Length = LogRootPrefix->Length; } else { FullName->Buffer[0] = UNICODE_PATH_SEP; FullName->Length = sizeof(UNICODE_PATH_SEP); }
DnrConcatenateFilePath( FullName, FileName->Buffer, FileName->Length);
}
//+----------------------------------------------------------------------------
//
// Function: DnrCaptureCredentials
//
// Synopsis: Captures the credentials to use for Dnr.
//
// Arguments: [DnrContext] -- The DNR_CONTEXT record describing the Dnr.
//
// Returns: Nothing -- The DnrContext is simply updated.
//
//-----------------------------------------------------------------------------
VOID DnrCaptureCredentials( IN OUT PDNR_CONTEXT DnrContext) {
#ifdef TERMSRV
NTSTATUS Status; ULONG SessionID; #endif // TERMSRV
LUID LogonID;
DfsDbgTrace(+1, Dbg, "DnrCaptureCredentials: Enter [%wZ] \n", &DnrContext->FileName); ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
DfsGetLogonId( &LogonID );
#ifdef TERMSRV
Status = TSGetRequestorSessionId( DnrContext->OriginalIrp, & SessionID );
ASSERT( NT_SUCCESS( Status ) ) ;
if( NT_SUCCESS( Status ) ) { DnrContext->Credentials = DfsLookupCredentials( &DnrContext->FileName, SessionID, &LogonID ); } else { DnrContext->Credentials = NULL; }
#else // TERMSRV
DnrContext->Credentials = DfsLookupCredentials( &DnrContext->FileName, &LogonID );
#endif // TERMSRV
if (DnrContext->Credentials != NULL) DnrContext->Credentials->RefCount++;
ExReleaseResourceLite( &DfsData.Resource ); DfsDbgTrace(-1, Dbg, "DnrCaptureCredentials: Exit. Creds %x\n", DnrContext->Credentials);
}
//+----------------------------------------------------------------------------
//
// Function: DnrReleaseCredentials
//
// Synopsis: Releases the credentials captured by DnrCaptureCredentials
//
// Arguments: [DnrContext] -- The DNR_CONTEXT into which credentials were
// captured.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DnrReleaseCredentials( IN PDNR_CONTEXT DnrContext) { ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
if (DnrContext->Credentials != NULL) DnrContext->Credentials->RefCount--;
ExReleaseResourceLite( &DfsData.Resource );
}
//+-------------------------------------------------------------------
//
// Function: DnrRedirectFileOpen, local
//
// Synopsis: This routine redirects a create IRP request to the specified
// provider by doing an IoCallDriver to the device object for
// which the file open is destined. This routine takes care of
// converting the FileObject's name from the Dfs namespace to
// the underlying file system's namespace.
//
// Arguments: [DnrContext] -- The context block for the DNR. All
// parameters for the operation will be taken from
// here.
//
// Returns: [STATUS_DEVICE_OFF_LINE] -- The service for the volume
// is currently off line.
//
// [STATUS_DEVICE_NOT_CONNECTED] -- The storage for the volume
// is not available at this time. Might have been blown
// off by a format etc.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate room
// for the file name that the provider for this volume
// understands.
//
// [STATUS_PENDING] -- If the underlying file system returned
// STATUS_PENDING.
//
// Any other NTSTATUS that the underlying file system returned.
//
// Notes:
//
//--------------------------------------------------------------------
NTSTATUS DnrRedirectFileOpen ( IN PDNR_CONTEXT DnrContext ) { PIRP Irp = DnrContext->OriginalIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION NextIrpSp = NULL; PFILE_OBJECT FileObject = IrpSp->FileObject; PDFS_VCB Vcb = DnrContext->Vcb; NTSTATUS Status; UNICODE_STRING fileName; ULONG CreateOptions; PPROVIDER_DEF pProvider; UNICODE_STRING ProviderDeviceName;
DfsDbgTrace(+1, Dbg, "DnrRedirectFileOpen: Entered\n", 0);
MUP_TRACE_NORM(DNR, DnrRedirectFileOpen_Entry, LOGPTR(DnrContext->OriginalIrp) LOGUSTR(DnrContext->FileName)); //
// If this is a csc agent open, force the open to the LanManRedirector,
// as this is the only redirector that works with csc.
//
DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry );
DnrContext->DfsNameContext.pLMRTargetInfo = NULL; DnrContext->DfsNameContext.pDfsTargetInfo = NULL;
if (DnrContext->pDfsTargetInfo != NULL) { if (DnrContext->pDfsTargetInfo->DfsHeader.Flags & TARGET_INFO_DFS) { DnrContext->DfsNameContext.pDfsTargetInfo = (PVOID)&DnrContext->pDfsTargetInfo->TargetInfo; } else { DnrContext->DfsNameContext.pLMRTargetInfo = (PVOID)&DnrContext->pDfsTargetInfo->LMRTargetInfo; } }
if ( (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) && (DnrContext->pService->Type & DFS_SERVICE_TYPE_DOWN_LEVEL) ) { RtlInitUnicodeString(&ProviderDeviceName, DD_NFS_DEVICE_NAME_U); ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE ); Status = DfsGetProviderForDevice( &ProviderDeviceName, &DnrContext->pProvider); if (NT_SUCCESS( Status )) { DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); if (MupVerbose) DbgPrint(" CSCAGENT:Provider Device [%wZ] -> [%wZ]\n", &DnrContext->TargetDevice->DriverObject->DriverName, &DnrContext->pProvider->DeviceObject->DriverObject->DriverName); DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice); } else { DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); ExReleaseResourceLite( &DfsData.Resource ); DnrReleaseAuthenticatedConnection(DnrContext); DnrContext->FinalStatus = STATUS_BAD_NETWORK_PATH; DnrContext->State = DnrStateDone; return(STATUS_BAD_NETWORK_PATH); } ExReleaseResourceLite( &DfsData.Resource ); }
//
// Prepare to hand of the open request to the next driver. We
// must give it a name that it will understand; so, we save the original
// file name in the DnrContext in case we need to restore it in the
// event of a failure.
//
DnrContext->SavedFileName = FileObject->FileName; DnrContext->SavedRelatedFileObject = FileObject->RelatedFileObject;
ASSERT( DnrContext->SavedFileName.Buffer != NULL );
//
// Create the full path name to be opened from the target device
// object.
//
fileName.MaximumLength = DnrContext->pService->Address.Length + DnrContext->pPktEntry->Id.Prefix.Length + sizeof (WCHAR) + DnrContext->RemainingPart.Length;
fileName.Buffer = ExAllocatePoolWithTag(PagedPool, fileName.MaximumLength, ' puM');
if (fileName.Buffer == NULL) { DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice); DnrReleaseAuthenticatedConnection(DnrContext); DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; DnrContext->State = DnrStateDone; return(STATUS_INSUFFICIENT_RESOURCES); }
if (DnrContext->pService->Address.Buffer) {
RtlMoveMemory( fileName.Buffer, DnrContext->pService->Address.Buffer, DnrContext->pService->Address.Length ); fileName.Length = DnrContext->pService->Address.Length;
} else {
fileName.Buffer[0] = UNICODE_PATH_SEP; fileName.Length = sizeof(WCHAR);
}
//
// If we are supposed to strip the prefix, do it now.
//
if (!(DnrContext->pService->Capability & PROV_STRIP_PREFIX)) {
DnrConcatenateFilePath( &fileName, DnrContext->pPktEntry->Id.Prefix.Buffer, DnrContext->pPktEntry->Id.Prefix.Length);
}
if (DnrContext->RemainingPart.Length > 0) {
DnrConcatenateFilePath( &fileName, DnrContext->RemainingPart.Buffer, DnrContext->RemainingPart.Length);
}
DnrContext->NewNameLen = fileName.Length;
//
// Attempt to open the file. Copy all of the information
// from the create IRP we received.
//
DfsDbgTrace( 0, Dbg, "Attempt to open %wZ\n", &fileName );
//
// Copy the stack from one to the next...
//
NextIrpSp = IoGetNextIrpStackLocation(Irp); (*NextIrpSp) = (*IrpSp);
CreateOptions = IrpSp->Parameters.Create.Options;
// Update the type of open in the DfsNameContext
if (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) { #if DBG
if (MupVerbose) DbgPrint(" FsContext = DFS_CSCAGENT_NAME_CONTEXT\n"); #endif
DnrContext->DfsNameContext.NameContextType = DFS_CSCAGENT_NAME_CONTEXT; } else { #if DBG
if (MupVerbose) DbgPrint(" FsContext = DFS_USER_NAME_CONTEXT\n"); #endif
DnrContext->DfsNameContext.NameContextType = DFS_USER_NAME_CONTEXT; }
FileObject->FsContext = &(DnrContext->DfsNameContext);
if (DnrContext->pProvider->fProvCapability & PROV_DFS_RDR) {
//
// We are connecting to a dfs-aware server. Indicate this to the
// redirector.
//
FileObject->FsContext2 = UIntToPtr(DFS_OPEN_CONTEXT);
} else {
//
// We are connecting to a downlevel server. Indicate to the redirector
// that Dfs is trying a downlevel access.
//
FileObject->FsContext2 = UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT);
}
NextIrpSp->Parameters.Create.Options = CreateOptions;
FileObject->RelatedFileObject = NULL; FileObject->FileName = fileName;
IoSetCompletionRoutine( Irp, DnrCompleteFileOpen, DnrContext, TRUE, TRUE, TRUE);
//
// Now, we are going to pass the buck to the provider for this volume.
// This can potentially go over the net. To avoid needless contentions,
// we release the Pkt.
//
ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
#if defined (USECOUNT_DBG)
{ LONG Count; Count = InterlockedIncrement(&DnrContext->pService->pMachEntry->UseCount); if (Count < DnrContext->pService->pMachEntry->SvcUseCount) { DbgPrint("DnrContext %x, 1\n", DnrContext); DfsDbgBreakPoint; } }
#else
InterlockedIncrement(&DnrContext->pService->pMachEntry->UseCount); #endif
DnrContext->FcbToUse->DfsMachineEntry = DnrContext->pService->pMachEntry; DnrContext->FcbToUse->TargetDevice = DnrContext->TargetDevice; DnrContext->FcbToUse->ProviderId = DnrContext->ProviderId;
PktRelease(); DnrContext->ReleasePkt = FALSE;
#if DBG
if (MupVerbose) DbgPrint(" DnrRedirectFileOpen of [%wZ(%wZ):0x%x] to [%wZ]\n", &fileName, &DnrContext->DfsNameContext.UNCFileName, DnrContext->DfsNameContext.Flags, &DnrContext->TargetDevice->DriverObject->DriverName); #endif
MUP_TRACE_NORM(DNR, DnrRedirectFileOpen_BeforeIoCallDriver, LOGPTR(Irp) LOGUSTR(DnrContext->FileName) LOGUSTR(DnrContext->TargetDevice->DriverObject->DriverName));
Status = IoCallDriver(DnrContext->TargetDevice, Irp); MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrRedirectFileOpen_Error_IoCallDriver, LOGSTATUS(Status) LOGPTR(Irp) LOGPTR(FileObject) LOGPTR(DnrContext)); if (Status != STATUS_PENDING) {
DnrContext->State = DnrStatePostProcessOpen;
}
DfsDbgTrace( 0, Dbg, "IoCallDriver Status = %8lx\n", ULongToPtr(Status));
DfsDbgTrace(-1, Dbg, "DnrRedirectFileOpen: Exit -> %x\n", ULongToPtr(Status));
return(Status);
}
//+-------------------------------------------------------------------
//
// Function: DnrPostProcessFileOpen, local
//
// Synopsis: This routine picks up where DnrRedirectFileOpen left off.
// It figures out what the underlying file system returned
// in response to our IoCallDriver, and resumes DNR from there.
//
// Arguments: [DnrContext] -- The context block for the DNR. All
// parameters for the operation will be taken from
// here.
//
// Returns: NTSTATUS - The status of the operation.
//
//--------------------------------------------------------------------
ULONG StopOnError = 0;
NTSTATUS DnrPostProcessFileOpen( IN PDNR_CONTEXT DnrContext) { NTSTATUS Status; PDFS_VCB Vcb = DnrContext->Vcb; PIRP Irp = DnrContext->OriginalIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; LARGE_INTEGER EndTime;
DfsDbgTrace( +1, Dbg, "DnrPostProcessFileOpen Entered: DnrContext = %08lx\n", DnrContext );
Status = DnrContext->FinalStatus;
if ((Status == STATUS_LOGON_FAILURE) || (Status == STATUS_ACCESS_DENIED)) { if (MupVerbose) { DbgPrint("File %wZ, (%wZ), Status %x\n", &DnrContext->ContextFileName, &FileObject->FileName, Status); DbgPrint("Context used was %x, %x\n", DnrContext->DfsNameContext.pDfsTargetInfo, DnrContext->DfsNameContext.pLMRTargetInfo ); DbgPrint("Driver is %wZ\n", &DnrContext->TargetDevice->DriverObject->DriverName); } } #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrPostProcessFileOpen entered [%wZ] Status = 0x%x\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), &FileObject->FileName, Status); } #endif
if ( Status == STATUS_REPARSE ) {
//
// This may have been an open sent to the MUP, who is now returning a status
// reparse. Figure out the name of the device that this is being
// reparsed to, create (if needed) a PROVIDER_DEF for this new device,
// and retry DnrRedirectFileOpen. Also, update the service
// structure to point to this new provider.
//
//
// If the device is not mup, clean out any child entries for the pkt
// entry that represents the root of the dfs, then stop dnr with
// STATUS_REPARSE
//
PDFS_PKT_ENTRY pEntry; UNICODE_STRING ProviderDevice; UNICODE_STRING MupDeviceName; UNICODE_STRING FileName; UNICODE_STRING RemPath; USHORT i, j;
DfsDbgTrace(0, Dbg, "Processing STATUS_REPARSE...\n", 0);
ProviderDevice = FileObject->FileName;
RtlInitUnicodeString(&MupDeviceName, L"\\FileSystem\\Mup");
#if DBG
if (MupVerbose) DbgPrint(" Comparing [%wZ] to [%wZ]\n", &DnrContext->TargetDevice->DriverObject->DriverName, &MupDeviceName); #endif
if ( RtlCompareUnicodeString( &DnrContext->TargetDevice->DriverObject->DriverName, &MupDeviceName, TRUE) != 0 ) {
//
// This is *not* the mup returning REPARSE
//
FileName = DnrContext->FileName;
//
// We want to work with the \Server\Share part of the FileName only,
// so count up to 3 backslashes, then stop.
//
for (i = j = 0; i < FileName.Length/sizeof(WCHAR) && j < 3; i++) {
if (FileName.Buffer[i] == UNICODE_PATH_SEP) {
j++;
}
}
FileName.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
#if DBG
if (MupVerbose) DbgPrint(" Will remove all children of [%wZ]\n", &FileName); #endif
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
//
// Now find the pkt entry
//
pEntry = PktLookupEntryByPrefix( &DfsData.Pkt, &FileName, &RemPath);
//
// And remove all children
//
if (pEntry != NULL) {
PktFlushChildren(pEntry);
}
PktRelease(); DnrContext->ReleasePkt = FALSE;
DnrContext->GotReparse = TRUE; DnrContext->State = DnrStateDone; Status = STATUS_REPARSE;
} else {
//
// This is the mup returning REPARSE
//
//
// We want to work with the \Device\Driver part of the ProviderDevice only,
// so count up to 3 backslashes, then stop.
//
for (i = j = 0; i < ProviderDevice.Length/sizeof(WCHAR) && j < 3; i++) {
if (ProviderDevice.Buffer[i] == UNICODE_PATH_SEP) {
j++;
}
}
ProviderDevice.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
DfsDbgTrace(0, Dbg, "Provider Device is [%wZ]\n", &ProviderDevice);
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
Status = DfsGetProviderForDevice( &ProviderDevice, &DnrContext->pProvider);
if (NT_SUCCESS( Status )) {
DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice); DnrContext->State = DnrStateSendRequest;
} else {
if (DnrContext->FinalStatus != STATUS_REPARSE) { DnrContext->FinalStatus = Status; } DnrContext->State = DnrStateDone;
}
ExReleaseResourceLite( &DfsData.Resource );
}
ASSERT(DnrContext->ReleasePkt == FALSE);
//
// Set active service only if we're going to
// continue DNR, and the USN hasn't changed.
//
// The exit code (see comment at end) will restart DNR if the USN
// has changed.
//
if (NT_SUCCESS( Status )) {
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
if (DnrContext->USN == DnrContext->pPktEntry->USN) {
ReplSetActiveService(DnrContext->pPktEntry, DnrContext->RSelectContext);
DnrContext->pService->ProviderId = DnrContext->pProvider->eProviderId;
DnrContext->pService->pProvider = DnrContext->pProvider; }
PktConvertExclusiveToShared();
} else { if (Status == STATUS_FS_DRIVER_REQUIRED) { Status = STATUS_REPARSE; }
DnrContext->FinalStatus = Status; PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
}
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
#if defined (USECOUNT_DBG)
{ LONG Count; Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount); if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount) { DbgPrint("DnrContext %x, 2\n", DnrContext); DfsDbgBreakPoint; } } #else
InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount); #endif
DfsDbgTrace(0, Dbg, "State after Reparse is %d\n", DnrContext->State);
} else if (( Status == STATUS_LOGON_FAILURE ) || (Status == STATUS_ACCESS_DENIED)) { UNICODE_STRING ProviderDeviceName; UNICODE_STRING MupDeviceName; UNICODE_STRING ProviderDevice; BOOLEAN ReturnError = FALSE;
NTSTATUS SavedStatus = Status;
ProviderDevice = FileObject->FileName; RtlInitUnicodeString(&MupDeviceName, L"\\FileSystem\\Mup");
if ( RtlCompareUnicodeString( &DnrContext->TargetDevice->DriverObject->DriverName, &MupDeviceName, TRUE) == 0 ) {
RtlInitUnicodeString(&ProviderDeviceName, DD_NFS_DEVICE_NAME_U); ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
Status = DfsGetProviderForDevice( &ProviderDeviceName, &DnrContext->pProvider);
if (Status == STATUS_SUCCESS) { DnrContext->ProviderId = DnrContext->pProvider->eProviderId; DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject; DFS_REFERENCE_OBJECT(DnrContext->TargetDevice); DnrContext->State = DnrStateSendRequest; } ExReleaseResourceLite( &DfsData.Resource ); if (Status == STATUS_SUCCESS) { PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
if (DnrContext->USN == DnrContext->pPktEntry->USN) {
ReplSetActiveService(DnrContext->pPktEntry, DnrContext->RSelectContext);
DnrContext->pService->ProviderId = DnrContext->pProvider->eProviderId;
DnrContext->pService->pProvider = DnrContext->pProvider; }
PktConvertExclusiveToShared();
} }
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
if (Status != STATUS_SUCCESS) { DnrContext->FinalStatus = SavedStatus; DnrContext->State = DnrStateDone;
ExFreePool( FileObject->FileName.Buffer ); FileObject->FileName = DnrContext->SavedFileName; FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject; } } else if ( Status == STATUS_OBJECT_TYPE_MISMATCH ) {
//
// This was an open sent to a downlevel server\share that failed
// because the server happens to be in a Dfs itself. If so, we
// simply change the name on which we are doing DNR and restart DNR.
//
DfsDbgTrace(0, Dbg, "Downlevel access found inter-dfs link!\n", 0);
DfsDbgTrace( 0, Dbg, "Current File name is [%wZ]\n", &FileObject->FileName);
ASSERT(DnrContext->ReleasePkt == FALSE); PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
//
// Bug: 332061. do not mark it as outside my dom.
//
// DnrContext->pPktEntry->Type |= PKT_ENTRY_TYPE_OUTSIDE_MY_DOM;
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
#if defined (USECOUNT_DBG)
{ LONG Count; Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount); if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount) { DbgPrint("DnrContext %x, 3\n", DnrContext); DfsDbgBreakPoint; } } #else
InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
#endif
DnrContext->RemainingPart.Length = 0; DnrContext->RemainingPart.MaximumLength = 0; DnrContext->RemainingPart.Buffer = 0;
DnrRebuildDnrContext( DnrContext, &FileObject->FileName, &DnrContext->RemainingPart);
ExFreePool(FileObject->FileName.Buffer); FileObject->FileName = DnrContext->SavedFileName; FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject;
} else if ( NT_SUCCESS( Status ) ) {
PDFS_FCB Fcb; DfsDbgTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
ASSERT( (DnrContext->FileName.Length & 0x1) == 0 );
Fcb = DnrContext->FcbToUse; DnrContext->FcbToUse = NULL;
DfsDbgTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
Fcb->TargetDevice = DnrContext->TargetDevice; Fcb->ProviderId = DnrContext->ProviderId;
//
// If we file (dir) happens to be a junction point, we capture its
// alternate name from the Pkt Entry, so we can field requests for
// FileAlternateNameInformation.
//
if (DnrContext->RemainingPart.Length == 0) {
UNICODE_STRING allButLast; USHORT UseLength;
RemoveLastComponent( &DnrContext->pPktEntry->Id.ShortPrefix, &allButLast);
//
// 587769: Set alternate path only if we have enough
// space in target buffer.
//
UseLength = DnrContext->pPktEntry->Id.ShortPrefix.Length - allButLast.Length;
if (Fcb->AlternateFileName.MaximumLength > UseLength) { Fcb->AlternateFileName.Length = UseLength;
RtlCopyMemory( Fcb->AlternateFileName.Buffer, &DnrContext->pPktEntry->Id.ShortPrefix.Buffer[allButLast.Length/sizeof(WCHAR)], Fcb->AlternateFileName.Length);
DfsDbgTrace( 0, Dbg, "Captured alternate name [%wZ]\n", &Fcb->AlternateFileName); }
}
InterlockedIncrement(&Fcb->Vcb->OpenFileCount);
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
if (DnrContext->USN == DnrContext->pPktEntry->USN) { ReplSetActiveService(DnrContext->pPktEntry, DnrContext->RSelectContext); }
//
// Reset the life time since we just used this PKT entry successfully.
//
DnrContext->pPktEntry->ExpireTime = DnrContext->pPktEntry->TimeToLive;
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
PktConvertExclusiveToShared();
DnrContext->FinalStatus = Status; DnrContext->State = DnrStateDone;
ExFreePool( DnrContext->SavedFileName.Buffer );
} else { // ! NT_SUCCESS( Status ) on IoCallDriver
DfsDbgTrace( 0, Dbg, "Open attempt failed %8lx\n", ULongToPtr(Status) );
if (Status == STATUS_PATH_NOT_COVERED || Status == STATUS_DFS_EXIT_PATH_FOUND) {
if (DnrContext->GotReferral) {
//
// We just got a referral, and the server is saying
// path_not_covered. Means DC and server are out
// of sync. Inform the DC
//
DfsDbgTrace(0, Dbg, "Dnr: Knowledge inconsistency discovered %wZ\n", &FileObject->FileName); (VOID) DfsTriggerKnowledgeVerification( DnrContext );
//
// If we never found an inconsistency let us now
// go back and try to see if we got this fixed.
// We won't be in an endless loop since we will
// not do this more than once.
//
if (DnrContext->FoundInconsistency == FALSE) { DnrContext->State = DnrStateGetFirstReplica; DnrContext->FoundInconsistency = TRUE; } else DnrContext->State = DnrStateGetNextReplica; } else { DnrContext->State = DnrStateGetFirstDC; }
} else if (ReplIsRecoverableError( Status )) {
//
// Check to see if the error returned was something worth
// trying a replica for.
//
DnrContext->State = DnrStateGetNextReplica; #if DBG
if (MupVerbose) DbgPrint(" Recoverable error 0x%x State = DnrStateGetNextReplica\n", Status); #endif
} else if ((Status == STATUS_OBJECT_PATH_NOT_FOUND) && (DnrContext->RemainingPart.Length == 0)) {
//
// if we hit a PATH_NOT_FOUND at the root, it usually means
// that we have hit a machine that is no longer the root.
// If there is only one target, mark it as expired.
// otherwise, move on to the other targets.
//
if (DnrContext->pPktEntry->Info.ServiceCount > 1) { DnrContext->State = DnrStateGetNextReplica; } else { DnrContext->pPktEntry->ExpireTime = 0; DnrContext->FinalStatus = Status; DnrContext->State = DnrStateDone; } } else {
DnrContext->FinalStatus = Status; DnrContext->State = DnrStateDone;
#if DBG
if (MupVerbose) DbgPrint(" NON-Recoverable error 0x%x State = DnrStateDone\n", Status); #endif
}
if (DfsEventLog > 0) { UNICODE_STRING puStr[2];
if (!DnrContext->ReleasePkt) PktAcquireShared( TRUE, &DnrContext->ReleasePkt ); if (DnrContext->USN == DnrContext->pPktEntry->USN) { puStr[0] = FileObject->FileName; puStr[1] = DnrContext->pService->Name; LogWriteMessage(DFS_OPEN_FAILURE, Status, 2, puStr); } }
//
// In either case, we are going back into DNR. Let's acquire shared
// access to Pkt. We had released the Pkt just before doing the
// IoCallDriver.
//
if (!DnrContext->ReleasePkt) PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
#if defined (USECOUNT_DBG)
{ LONG Count; Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount); if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount) { DbgPrint("DnrContext %x, 4\n", DnrContext); DfsDbgBreakPoint; } } #else
InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
#endif
ExFreePool( FileObject->FileName.Buffer ); FileObject->FileName = DnrContext->SavedFileName; FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject; }
//
// One last thing. If we are going back into DNR for whatever reason,
// check to see if the PktEntry we captured in the DNR_CONTEXT has
// changed. If so, we'll simply have to restart.
//
if (DnrContext->State != DnrStateDone && DnrContext->pPktEntry != NULL && DnrContext->pPktEntry->USN != DnrContext->USN) {
DnrContext->State = DnrStateStart;
}
#if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrPostProcessFileOpen Exited: Status = %08lx State = %d\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), Status, DnrContext->State); } #endif
DfsDbgTrace( -1, Dbg, "DnrPostProcessFileOpen Exited: Status = %08lx\n", ULongToPtr(Status) ); return Status; }
//+----------------------------------------------------------------------------
//
// Function: DnrGetAuthenticatedConnection
//
// Synopsis: If this Dnr is using user-supplied credentials, this routine
// will setup a tree connection using the user-supplied
// credentials.
//
// Notes: This routine might free and reacquire the Pkt lock. This
// means that the Pkt entry referenced in DnrContext might
// become invalid after this call. The caller is assumed to
// have cached and referenced everything she will need to
// use in DnrContext before making this call.
//
// Arguments: [DnrContext] -- The DNR_CONTEXT record for this Dnr
//
// Returns: [STATUS_SUCCESS] -- Operation completed successfully
//
// NT Status from the attempt to create the tree connection
//
//-----------------------------------------------------------------------------
NTSTATUS DnrGetAuthenticatedConnection( IN OUT PDNR_CONTEXT DnrContext) { NTSTATUS Status; PDFS_SERVICE pService = DnrContext->pService; BOOLEAN fDoConnection = TRUE; LARGE_INTEGER EndTime;
PFILE_OBJECT TreeConnFileObj = NULL;
DfsDbgTrace(+1, Dbg, "DnrGetAuthenticatedConnection: Entered\n", 0);
#if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrGetAuthenticatedConnection(\\%wZ)\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), &pService->Address); } #endif
ASSERT(DnrContext->pService != NULL); ASSERT(DnrContext->pProvider != NULL);
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
//
// See if we are using supplied credentials
//
if (DnrContext->Credentials == NULL) {
DfsDbgTrace(-1, Dbg, "DnrGetAuthenticatedConnection: Dnr with no creds\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrGetAuthenticatedConnection: No creds exit STATUS_SUCCESS\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ExReleaseResourceLite( &DfsData.Resource ); return( STATUS_SUCCESS ); }
//
// See if this is a credential record describing the use of default
// credentials
//
if (DnrContext->Credentials->EaLength == 0) {
DfsDbgTrace(-1, Dbg, "DnrGetAuthenticatedConnection: Dnr with default creds\n", 0); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrGetAuthenticatedConnection: Default creds exit STATUS_SUCCESS\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
ExReleaseResourceLite( &DfsData.Resource ); return( STATUS_SUCCESS );
}
//
// See if we already have a authenticated connection to the server, and
// the authenticated connection was established using the credentials
// we want to use.
//
if (pService->pMachEntry->AuthConn != NULL) {
if ( (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0 && pService->pMachEntry->Credentials == DnrContext->Credentials ) {
DnrContext->AuthConn = pService->pMachEntry->AuthConn; DFS_REFERENCE_OBJECT( DnrContext->AuthConn ); fDoConnection = FALSE; DfsDbgTrace(0, Dbg, "Using existing tree connect %08lx\n", DnrContext->AuthConn); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] Using existing tree connect\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
Status = STATUS_SUCCESS;
} else {
DfsDbgTrace(0, Dbg, "Deleting connect %08lx\n", pService->pMachEntry->AuthConn); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] Deleting tree connect connect\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000))); } #endif
TreeConnFileObj = pService->pMachEntry->AuthConn;
pService->pMachEntry->AuthConn = NULL; pService->pMachEntry->Credentials->RefCount--; pService->pMachEntry->Credentials = NULL; if (pService->ConnFile != NULL) DfsCloseConnection( pService );
}
}
ExReleaseResourceLite( &DfsData.Resource );
//
// We delete the tree connection after releasing the resource, since
// the delete involve a call to a lower level driver and we want to
// avoid resource lock conflicts.
//
if (TreeConnFileObj) { DfsDeleteTreeConnection( TreeConnFileObj, USE_FORCE ); }
//
// If we need to establish a new authenticated connection, do it now.
// We need a new connection because either we had none, or the one we
// had was using a different set of credentials.
//
if (fDoConnection) {
UNICODE_STRING shareName; HANDLE treeHandle; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; USHORT i, k;
//
// Compute the share name...
//
shareName.MaximumLength = sizeof(DD_NFS_DEVICE_NAME_U) + pService->Address.Length;
shareName.Buffer = ExAllocatePoolWithTag(PagedPool, shareName.MaximumLength, ' puM');
if (shareName.Buffer != NULL) {
shareName.Length = 0;
RtlAppendUnicodeToString( &shareName, DD_NFS_DEVICE_NAME_U);
RtlAppendUnicodeStringToString(&shareName, &pService->Address);
//
// One can only do tree connects to server\share. So, in case
// pService->Address refers to something deeper than the share,
// make sure we setup a tree-conn only to server\share. Note that
// by now, shareName is of the form
// \Device\LanmanRedirector\server\share<\path>. So, count up to
// 4 slashes and terminate the share name there.
//
for (i = 0, k = 0; i < shareName.Length/sizeof(WCHAR) && k < 5; i++) {
if (shareName.Buffer[i] == UNICODE_PATH_SEP) k++; }
shareName.Length = i * sizeof(WCHAR); if (k == 5) shareName.Length -= sizeof(WCHAR);
InitializeObjectAttributes( &objectAttributes, &shareName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
DfsDbgTrace(0, Dbg, "Tree connecting to %wZ\n", &shareName); DfsDbgTrace(0, Dbg, "Credentials @%08lx\n", DnrContext->Credentials);
Status = ZwCreateFile( &treeHandle, SYNCHRONIZE, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, (PVOID) DnrContext->Credentials->EaBuffer, DnrContext->Credentials->EaLength);
MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrGetAuthenticatedConnection_Error_ZwCreateFile, LOGSTATUS(Status));
#if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] Tree connect to [%wZ] returned 0x%x\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), &shareName, Status); } #endif
if (NT_SUCCESS(Status)) {
PFILE_OBJECT fileObject;
DfsDbgTrace(0, Dbg, "Tree connect succeeded\n", 0);
//
// 426184, need to check return code for errors.
//
Status = ObReferenceObjectByHandle( treeHandle, 0, NULL, KernelMode, (PVOID *)&fileObject, NULL); MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrGetAuthenticatedConnection_Error_ObReferenceObjectByHandle, LOGSTATUS(Status));
ZwClose( treeHandle );
if (NT_SUCCESS(Status)) { DnrContext->AuthConn = fileObject; } }
if (NT_SUCCESS(Status)) {
//
// We have a new tree connect. Lets try to cache it for later
// use. Note that the Pkt could have changed when we went out
// over the net to establish the tree connect, so we cache
// the tree connect only if the Pkt hasn't changed.
//
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt ); ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
if (DnrContext->USN == DnrContext->pPktEntry->USN) {
if (pService->pMachEntry->AuthConn == NULL) {
pService->pMachEntry->AuthConn = DnrContext->AuthConn;
DFS_REFERENCE_OBJECT( pService->pMachEntry->AuthConn );
pService->pMachEntry->Credentials = DnrContext->Credentials;
pService->pMachEntry->Credentials->RefCount++;
}
}
ExReleaseResourceLite( &DfsData.Resource );
DnrContext->ReleasePkt = FALSE; PktRelease(); }
ExFreePool( shareName.Buffer );
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
DfsDbgTrace(-1, Dbg, "DnrGetAuthenticatedConnection: Exit %08lx\n", ULongToPtr(Status) );
#if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint(" [%d] DnrGetAuthenticatedConnection exit 0x%x\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), Status); } #endif
return( Status );
}
//+----------------------------------------------------------------------------
//
// Function: DnrReleaseAuthenticatedConnection
//
// Synopsis: Dereferences the authenticated connection we used during
// Dnr.
//
// Arguments: [DnrContext] -- The DNR_CONTEXT record for this Dnr
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DnrReleaseAuthenticatedConnection( IN PDNR_CONTEXT DnrContext) { if (DnrContext->AuthConn != NULL) {
DFS_DEREFERENCE_OBJECT( DnrContext->AuthConn );
DnrContext->AuthConn = NULL;
} }
//+----------------------------------------------------------------------------
//
// Function: DfsBuildConnectionRequest
//
// Synopsis: Builds the file names necessary to setup an
// authenticated connection to a server's IPC$ share.
//
// Arguments: [pService] -- Pointer to DFS_SERVICE describing server
// [pProvider] -- Pointer to PROVIDER_DEF describing the
// provider to use to establish the connection.
// [pShareName] -- Share name to open.
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
//-----------------------------------------------------------------------------
NTSTATUS DfsBuildConnectionRequest( IN PDFS_SERVICE pService, IN PPROVIDER_DEF pProvider, OUT PUNICODE_STRING pShareName) { ASSERT(pService != NULL); ASSERT(pProvider != NULL);
RtlInitUnicodeString(pShareName, NULL);
pShareName->Length = 0;
pShareName->MaximumLength = pProvider->DeviceName.Length + sizeof(UNICODE_PATH_SEP_STR) + pService->Name.Length + sizeof(ROOT_SHARE_NAME);
pShareName->Buffer = ExAllocatePoolWithTag(PagedPool, pShareName->MaximumLength, ' puM');
if (pShareName->Buffer == NULL) {
DfsDbgTrace(0, Dbg, "Unable to allocate pool for share name!\n", 0);
pShareName->Length = pShareName->MaximumLength = 0;
return( STATUS_INSUFFICIENT_RESOURCES ); }
RtlAppendUnicodeStringToString( pShareName, &pProvider->DeviceName );
RtlAppendUnicodeToString( pShareName, UNICODE_PATH_SEP_STR );
RtlAppendUnicodeStringToString( pShareName, &pService->Name );
RtlAppendUnicodeToString( pShareName, ROOT_SHARE_NAME );
return( STATUS_SUCCESS );
}
//+----------------------------------------------------------------------------
//
// Function: DfsFreeConnectionRequest
//
// Synopsis: Frees up the stuff allocated on a successful call to
// DfsBuildConnectionRequest
//
// Arguments: [pShareName] -- Unicode string holding share name.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsFreeConnectionRequest( IN OUT PUNICODE_STRING pShareName) {
if (pShareName->Buffer != NULL) { ExFreePool ( pShareName->Buffer ); } }
//+-------------------------------------------------------------------------
//
// Function: DfsCreateConnection -- Create a connection to a server
//
// Synopsis: DfsCreateConnection will attempt to create a connection
// to some server's IPC$ share.
//
// Arguments: [pService] -- the Service entry, giving the server principal
// name
// [pProvider] --
//
// [CSCAgentCreate] -- TRUE if this is on behalf of CSC agent
//
// [remoteHandle] -- This is where the handle is returned.
//
// Returns: NTSTATUS - the status of the operation
//
// Notes: The Pkt must be acquired shared before calling this! It will
// be released and reacquired in this routine.
//
//--------------------------------------------------------------------------
NTSTATUS DfsCreateConnection( IN PDFS_SERVICE pService, IN PPROVIDER_DEF pProvider, IN BOOLEAN CSCAgentCreate, OUT PHANDLE remoteHandle ) { PFILE_FULL_EA_INFORMATION EaBuffer; ULONG EaBufferLength; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING ShareName; NTSTATUS Status; BOOLEAN pktLocked;
ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() ); ASSERT(pService != NULL); ASSERT(pProvider != NULL);
Status = DfsBuildConnectionRequest( pService, pProvider, &ShareName);
if (!NT_SUCCESS(Status)) { return( Status ); }
InitializeObjectAttributes( &ObjectAttributes, &ShareName, // File Name
OBJ_KERNEL_HANDLE, // Attributes
NULL, // Root Directory
NULL // Security
);
//
// Create or open a connection to the server.
//
PktRelease();
if (CSCAgentCreate) { EaBuffer = DfsData.CSCEaBuffer; EaBufferLength = DfsData.CSCEaBufferLength; } else { EaBuffer = NULL; EaBufferLength = 0; }
Status = ZwCreateFile( remoteHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, EaBuffer, EaBufferLength);
MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCreateConnection_Error_ZwCreateFile, LOGSTATUS(Status)); PktAcquireShared( TRUE, &pktLocked );
if ( NT_SUCCESS( Status ) ) { DfsDbgTrace(0, Dbg, "Created Connection Successfully\n", 0); Status = IoStatusBlock.Status; }
DfsFreeConnectionRequest( &ShareName );
return Status; }
//+-------------------------------------------------------------------------
//
// Function: DfsCloseConnection -- Close a connection to a server
//
// Synopsis: DfsCloseConnection will attempt to Close a connection
// to some server.
//
// Effects: The file object referring to the the connection will be
// closed.
//
// Arguments: [pService] - the Service entry, giving the server connection
// handle
//
// Returns: NTSTATUS - the status of the operation
//
// History: 28 May 1992 Alanw Created
//
//--------------------------------------------------------------------------
NTSTATUS DfsCloseConnection( IN PDFS_SERVICE pService ) { ASSERT( pService->ConnFile != NULL );
ObDereferenceObject(pService->ConnFile); pService->ConnFile = NULL; InterlockedDecrement(&pService->pMachEntry->ConnectionCount); return STATUS_SUCCESS; }
//+----------------------------------------------------------------------------
//
// Function: DnrBuildReferralRequest
//
// Synopsis: This routine builds all the necessary things to send
// a referral request to a DC.
//
// Arguments: [pDnrContext] -- The context for building the referral.
//
// Returns: Pointer to an IRP that can be used to get a referral.
//
//-----------------------------------------------------------------------------
PIRP DnrBuildReferralRequest( IN PDNR_CONTEXT DnrContext) { PUCHAR pNameResBuf = NULL; PREQ_GET_DFS_REFERRAL pRef; PWCHAR ReferralPath; PPROVIDER_DEF pProvider; PIRP pIrp = NULL; ULONG cbBuffer = 0; NTSTATUS Status;
DfsDbgTrace(+1,Dbg, "DnrBuildReferralRequest Entered - DnrContext %08lx\n", DnrContext);
cbBuffer = DnrContext->FileName.Length + sizeof(UNICODE_NULL) + sizeof(PREQ_GET_DFS_REFERRAL);
if (DnrContext->ReferralSize > cbBuffer) { cbBuffer = DnrContext->ReferralSize; } else { DnrContext->ReferralSize = cbBuffer; } DfsDbgTrace(0, Dbg, "Referral Size = %d bytes\n", ULongToPtr(cbBuffer));
pNameResBuf = ExAllocatePoolWithTag(NonPagedPool, cbBuffer, ' puM');
if (pNameResBuf == NULL) { DfsDbgTrace(-1, Dbg, "Unable to allocate %d bytes\n", ULongToPtr(cbBuffer)); return( NULL );
}
pRef = (PREQ_GET_DFS_REFERRAL) pNameResBuf;
pRef->MaxReferralLevel = 3;
ReferralPath = (PWCHAR) &pRef->RequestFileName[0];
RtlMoveMemory( ReferralPath, DnrContext->FileName.Buffer, DnrContext->FileName.Length);
ReferralPath[ DnrContext->FileName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
ASSERT( DnrContext->DCConnFile != NULL);
#if DBG
if (MupVerbose) DbgPrint(" DnrBuildReferrlRequest:ReferralPath=[%ws]\n", ReferralPath); #endif
Status = DnrGetTargetInfo( DnrContext );
if (Status == STATUS_SUCCESS) { pIrp = DnrBuildFsControlRequest( DnrContext->DCConnFile, DnrContext, FSCTL_DFS_GET_REFERRALS, pNameResBuf, FIELD_OFFSET(REQ_GET_DFS_REFERRAL, RequestFileName) + (wcslen(ReferralPath) + 1) * sizeof(WCHAR), pNameResBuf, cbBuffer, DnrCompleteReferral ); if (pIrp == NULL) {
DfsDbgTrace(-1, Dbg, "DnrBuildReferralRequest: Unable to allocate Irp!\n", 0); ExFreePool(pNameResBuf);
} else { DfsDbgTrace(-1, Dbg, "DnrBuildReferralRequest: returning %08lx\n", pIrp); } } return( pIrp );
}
//+----------------------------------------------------------------------------
//
// Function: DnrInsertReferralAndResume
//
// Synopsis: This routine is queued as a work item from DnrComplete
// referral and does the work of actually inserting the
// referral and resuming DNR. We must not do this work
// directly in DnrCompleteReferral because it operates at
// raised IRQL.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
VOID DnrInsertReferralAndResume( IN PVOID Context) { PIRP_CONTEXT pIrpContext = (PIRP_CONTEXT) Context; PDNR_CONTEXT DnrContext = (PDNR_CONTEXT) pIrpContext->Context; PIRP Irp = pIrpContext->OriginatingIrp; PRESP_GET_DFS_REFERRAL pRefResponse; ULONG length, matchingLength; NTSTATUS status; LARGE_INTEGER EndTime; ULONG referralType = 0; NTSTATUS DiscardStatus;
DfsDbgTrace(+1, Dbg, "DnrInsertReferralAndResume: Entered\n", 0); DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp ); DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
ASSERT(DnrContext->State == DnrStateCompleteReferral);
status = Irp->IoStatus.Status; length = (ULONG)Irp->IoStatus.Information;
DfsDbgTrace(0, Dbg, "Irp->Status = %x\n", ULongToPtr(status) ); DfsDbgTrace(0, Dbg, "Irp->Length = %x\n", ULongToPtr(length) );
KeQuerySystemTime(&EndTime);
#if DBG
if (MupVerbose) DbgPrint(" [%d] DnrInsertReferralAndResume entered for [%wZ] status = 0x%x\n", (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)), &DnrContext->FileName, status); #endif
//
// If the DC returned STATUS_BUFFER_OVERFLOW, the referral didn't fit in
// the buffer we sent. Increase the buffer and retry the referral request
// Since we are going to retry the request, we won't dereference the
// provider's device object yet.
//
if (status == STATUS_BUFFER_OVERFLOW) { PULONG pcbSize;
if (DnrContext->ReferralSize < MAX_REFERRAL_MAX) { DfsDbgTrace(0, Dbg, "Referral buffer was too small; retrying...\n", 0); DnrContext->ReferralSize = MAX_REFERRAL_MAX; DnrContext->State = DnrStateGetReferrals;
//
// Going back into Dnr. Reacquire the Pkt shared, and release the
// PktReferralRequests semaphore, so we can go out again to get a
// referral.
//
goto Cleanup; } }
//
// If we got an error and we were using a cached IPC$ connection,
// close the cached IPC$ and retry the referral request.
//
if ( (DnrContext->CachedConnFile == TRUE) && (status != STATUS_SUCCESS) ) {
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt ); ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE); DnrContext->CachedConnFile = FALSE; if (DnrContext->pService->ConnFile != NULL) { DfsCloseConnection(DnrContext->pService); } DnrContext->State = DnrStateGetReferrals; ExReleaseResourceLite( &DfsData.Resource ); PktConvertExclusiveToShared(); //
// Going back into Dnr. Reacquire the Pkt shared, and release the
// PktReferralRequests semaphore, so we can go out again to get a
// referral.
//
goto Cleanup; }
//
// The referral request has terminated. Since we are done with the
// provider, dereference its device object now.
//
DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
//
// Next, handle the result of the Referral request. If we successfully
// got a referral, then try to insert it into our Pkt.
//
if (NT_SUCCESS(status) && length != 0) {
pRefResponse = (PRESP_GET_DFS_REFERRAL) Irp->AssociatedIrp.SystemBuffer; DfsDbgTrace(0, Dbg, "Irp->Buffer = %x\n", pRefResponse );
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
status = PktCreateEntryFromReferral( &DfsData.Pkt, &DnrContext->FileName, length, pRefResponse, PKT_ENTRY_SUPERSEDE, DnrContext->pNewTargetInfo, &matchingLength, &referralType, &DnrContext->pPktEntry);
DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry );
if (status == STATUS_INVALID_USER_BUFFER) { status = STATUS_BAD_NETWORK_NAME; }
if (NT_SUCCESS(status) && DfsEventLog > 1) { UNICODE_STRING puStr[2];
puStr[0] = DnrContext->FileName; puStr[1] = DnrContext->pService->Name; LogWriteMessage(DFS_REFERRAL_SUCCESS, status, 2, puStr); }
if (NT_SUCCESS(status)) {
UNICODE_STRING fileName; UNICODE_STRING RemPath; PDFS_PKT_ENTRY pEntry = NULL; PDFS_PKT_ENTRY pShortPfxEntry = NULL; PDFS_PKT Pkt;
//
// See if we have to remove an entry
//
pEntry = PktLookupEntryByPrefix( &DfsData.Pkt, &DnrContext->FileName, &RemPath);
pShortPfxEntry = PktLookupEntryByShortPrefix( &DfsData.Pkt, &DnrContext->FileName, &RemPath);
if (pShortPfxEntry != NULL) { if ((pEntry == NULL) || (pShortPfxEntry->Id.Prefix.Length > pEntry->Id.Prefix.Length)) { pEntry = pShortPfxEntry; } }
if (pEntry != NULL && pEntry != DnrContext->pPktEntry) {
#if DBG
if (MupVerbose) DbgPrint(" DnrInsertReferralAndResume: Need to remove pEntry [%wZ]\n", &pEntry->Id.Prefix); #endif
Pkt = _GetPkt(); if ((pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) == 0) { PktFlushChildren(pEntry); if (pEntry->UseCount == 0) { PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE); } else { pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING; pEntry->ExpireTime = 0; DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix)); DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix)); } }
}
//
// At this point, we are essentially in the same state as we were
// when we started DNR, except that we have one more Pkt entry to
// match against. Continue with name resolution, after fixing up
// DnrContext->RemainingPart to reflect the match with the new
// PktEntry.
//
fileName = DnrContext->FileName;
DnrContext->RemainingPart.Length = (USHORT) (fileName.Length - matchingLength);
DnrContext->RemainingPart.MaximumLength = (USHORT) (fileName.MaximumLength - matchingLength);
DnrContext->RemainingPart.Buffer = &fileName.Buffer[ matchingLength/sizeof(WCHAR) ];
DnrContext->GotReferral = TRUE;
DnrContext->State = DnrStateStart;
} else {
DnrContext->FinalStatus = status; DnrContext->State = DnrStateDone; }
PktConvertExclusiveToShared();
} else if (status == STATUS_NO_SUCH_DEVICE) {
UNICODE_STRING RemPath; PDFS_PKT_ENTRY pEntry = NULL; PDFS_PKT Pkt; BOOLEAN pktLocked;
//
// Check if there is a pkt entry (probably stale) that needs to be removed
//
#if DBG
if (MupVerbose) DbgPrint(" DnrInsertReferralAndResume: remove PKT entry for \\%wZ\n", &DnrContext->FileName); #endif
PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
Pkt = _GetPkt(); #if DBG
if (MupVerbose) DbgPrint(" Looking up %wZ\n", &DnrContext->FileName); #endif
pEntry = PktLookupEntryByPrefix( &DfsData.Pkt, &DnrContext->FileName, &RemPath); #if DBG
if (MupVerbose) DbgPrint(" pEntry=0x%x\n", pEntry); #endif
if (pEntry != NULL && (pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) == 0) { PktFlushChildren(pEntry); if (pEntry->UseCount == 0) { PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE); } else { pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING; pEntry->ExpireTime = 0; DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix)); DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix)); } }
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
DnrContext->FinalStatus = status; DnrContext->State = DnrStateDone;
PktConvertExclusiveToShared();
} else if (ReplIsRecoverableError(status)) {
DnrContext->State = DnrStateGetNextDC;
} else if (status == STATUS_BUFFER_OVERFLOW) {
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
DnrContext->FinalStatus = status;
DnrContext->State = DnrStateDone;
} else if (DnrContext->Attempts > 0) {
#if DBG
if (MupVerbose) DbgPrint(" DnrInsertReferralAndResume restarting Attempts = %d\n", DnrContext->Attempts); #endif
DnrContext->State = DnrStateStart;
} else {
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
DnrContext->FinalStatus = status;
DnrContext->State = DnrStateDone;
}
if ( !NT_SUCCESS(status) && DfsEventLog > 0) { UNICODE_STRING puStr[2];
if (!DnrContext->ReleasePkt) PktAcquireShared( TRUE, &DnrContext->ReleasePkt ); if (DnrContext->USN == DnrContext->pPktEntry->USN) { puStr[0] = DnrContext->FileName; puStr[1] = DnrContext->pService->Name; LogWriteMessage(DFS_REFERRAL_FAILURE, status, 2, puStr); } }
Cleanup:
//
// Cleanup referral stuff.
//
if (Irp->UserBuffer && Irp->UserBuffer != Irp->AssociatedIrp.SystemBuffer) ExFreePool( Irp->UserBuffer ); if (Irp->AssociatedIrp.SystemBuffer) { ExFreePool( Irp->AssociatedIrp.SystemBuffer ); }
IoFreeIrp(Irp); PktReleaseTargetInfo( DnrContext->pNewTargetInfo ); DnrContext->pNewTargetInfo = NULL; DfsDeleteIrpContext(pIrpContext);
//
// We are going back into Dnr, so prepare for that:
//
// - Reacquire PKT shared
// - Release the semaphore for referral requests, so that the next
// thread can get its referral.
// - Restart Dnr
//
if (!DnrContext->ReleasePkt) PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
ASSERT(DnrContext->ReleasePkt == TRUE);
#if DBG
if (MupVerbose) DbgPrint(" DnrInsertReferralAndResume next State=%d\n", DnrContext->State); #endif
DnrContext->Impersonate = TRUE; DnrContext->DnrActive = FALSE; DnrNameResolve(DnrContext); PsAssignImpersonationToken(PsGetCurrentThread(),NULL);
DfsDbgTrace(-1, Dbg, "DnrInsertReferralAndResume: Exit -> %x\n", ULongToPtr(status) );
}
//
// The following two functions are DPC functions which participate
// in the Distributed Name Resolution process. Each takes a
// PDNR_CONTEXT as input, transitions the state of the
// name resolution and any associated data structures, and
// invokes the next step of the process.
//
//+-------------------------------------------------------------------
//
// Function: DnrCompleteReferral, local
//
// Synopsis: This is the completion routine for processing a referral
// response. Cleanup the IRP and continue processing the name
// resolution request.
//
// Arguments: [pDevice] -- 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 DNR
// Context block.
//
// Returns: [STATUS_MORE_PROCESSING_REQUIRED] -- The referral Irp was
// constructed by Dnr and will be freed by us. So, we
// don't want the IO Subsystem to touch the Irp anymore.
//
// Notes: This routine executes at DPC level. We should do an absolutely
// minimum amount of work here.
//
//--------------------------------------------------------------------
NTSTATUS DnrCompleteReferral( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PVOID Context ) { PIRP_CONTEXT pIrpContext = NULL; PDNR_CONTEXT DnrContext = (PDNR_CONTEXT) Context;
DfsDbgTrace(+1, Dbg, "DnrCompleteReferral: Entered\n", 0);
DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp); DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
//
// Derefernce the file object over which we sent the referral request
//
DFS_DEREFERENCE_OBJECT( DnrContext->DCConnFile );
DnrContext->DCConnFile = NULL;
//
// Release the semaphore controlling number of referral requests
//
KeReleaseSemaphore( &DfsData.PktReferralRequests, 0, // Priority boost
1, // Increment semaphore amount
FALSE); // Won't call wait immediately
try {
pIrpContext = DfsCreateIrpContext(Irp, TRUE); if (pIrpContext == NULL) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); pIrpContext->Context = DnrContext;
ExInitializeWorkItem( &pIrpContext->WorkQueueItem, DnrInsertReferralAndResume, pIrpContext);
ExQueueWorkItem( &pIrpContext->WorkQueueItem, CriticalWorkQueue );
} except(DfsExceptionFilter(pIrpContext, GetExceptionCode(), GetExceptionInformation())) {
//
// Ok, we can't queue the work item and complete Dnr. So, we have
// to do two things. First of all, clean up the current Irp (ie,
// the Referral Irp), then complete the original Dnr Irp
//
//
// Cleanup referral stuff.
//
if (Irp->UserBuffer && Irp->UserBuffer != Irp->AssociatedIrp.SystemBuffer) ExFreePool( Irp->UserBuffer ); if (Irp->AssociatedIrp.SystemBuffer) { ExFreePool( Irp->AssociatedIrp.SystemBuffer ); }
IoFreeIrp(Irp); PktReleaseTargetInfo( DnrContext->pNewTargetInfo ); DnrContext->pNewTargetInfo = NULL;
if (pIrpContext) {
//
// Maybe this should be an assert that pIrpContext == NULL. If
// it is not NULL, then the Irp context was allocated, so who
// threw an exception anyway?
//
DfsDeleteIrpContext(pIrpContext); }
//
// Now, call Dnr to complete the original Irp
//
InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
DnrContext->DnrActive = FALSE; DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; DnrContext->State = DnrStateDone; DnrNameResolve(DnrContext); PsAssignImpersonationToken(PsGetCurrentThread(),NULL); }
//
// Return more processing required to the IO system so that it
// doesn't attempt further processing on the IRP. The IRP will be
// freed by DnrInsertReferralAndResume, or has already been freed
// if we couldn't queue up DnrInsertReferralAndResume
//
DfsDbgTrace(-1, Dbg, "DnrCompleteReferral: Exit -> %x\n", ULongToPtr(STATUS_MORE_PROCESSING_REQUIRED) );
UNREFERENCED_PARAMETER(pDevice);
return STATUS_MORE_PROCESSING_REQUIRED; }
//+-------------------------------------------------------------------
//
// Function: DnrCompleteFileOpen, local
//
// Synopsis: This is the completion routine for processing a file open
// request. Cleanup the IRP and continue processing the name
// resolution request.
//
// Arguments: [pDevice] -- 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 DNR
// Context block.
//
// Returns: [STATUS_MORE_PROCESSING_REQUIRED] -- We still have to finish
// the DNR, so we halt further completion of this Irp
// by returning STATUS_MORE_PROCESSING_REQUIRED.
//
//--------------------------------------------------------------------
NTSTATUS DnrCompleteFileOpen( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PVOID Context ) { PDNR_CONTEXT DnrContext; NTSTATUS status; PFILE_OBJECT FileObject; PIO_STACK_LOCATION IrpSp;
DfsDbgTrace(+1, Dbg, "DnrCompleteFileOpen: Entered\n", 0); DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp ); DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
DnrContext = Context;
status = Irp->IoStatus.Status;
DfsDbgTrace(0, Dbg, "Irp->Status = %x\n", ULongToPtr(status) );
DnrContext->FinalStatus = status;
DnrReleaseAuthenticatedConnection( DnrContext );
DFS_DEREFERENCE_OBJECT( DnrContext->TargetDevice );
IrpSp = IoGetCurrentIrpStackLocation(Irp); FileObject = IrpSp->FileObject;
//
// If STATUS_PENDING was initially returned for the IRP, then we need
// to restart DNR. So, we post a workitem into the FSP, giving it the
// DnrContext to resume the DNR.
//
// If STATUS_PENDING was not returned, then we simply stop the
// unwinding of the IRP stack by returning STATUS_MORE_PROCESSING_REQUIRED
// IoCallDriver will eventually return to DnrRedirectFileOpen, which
// will continue with the DNR.
//
if (Irp->PendingReturned) {
//
// Schedule a work item to resume DNR
//
DnrContext->Impersonate = TRUE; DnrContext->DnrActive = FALSE; DnrContext->State = DnrStatePostProcessOpen; ASSERT(DnrContext->pIrpContext->MajorFunction == IRP_MJ_CREATE); DnrContext->pIrpContext->Context = (PVOID) DnrContext;
//
// We need to call IpMarkIrpPending so the IoSubsystem will realize
// that our FSD routine returned STATUS_PENDING. We can't call this
// from the FSD routine itself because the FSD routine doesn't have
// access to the stack location when the underlying guy returns
// STATUS_PENDING
//
IoMarkIrpPending( Irp );
DfsFsdPostRequest(DnrContext->pIrpContext, DnrContext->OriginalIrp); }
//
// Return more processing required to the IO system so that it
// stops unwinding the completion routine stack. The DNR that will
// be resumed will call IoCompleteRequest when appropriate
// and resume the unwinding of the completion routine stack.
//
status = STATUS_MORE_PROCESSING_REQUIRED; DfsDbgTrace(-1, Dbg, "DnrCompleteFileOpen: Exit -> %x\n", ULongToPtr(status) );
UNREFERENCED_PARAMETER(pDevice);
return status; }
//+-------------------------------------------------------------------
//
// Function: DnrBuildFsControlRequest, local
//
// Synopsis: This function builds an I/O request packet for a device or
// file system I/O control request.
//
// Arguments: [FileObject] -- Supplies a pointer the file object to which this
// request is directed. This pointer is copied into the
// IRP, so that the called driver can find its file-based
// context. NOTE THAT THIS IS NOT A REFERENCED POINTER.
// The caller must ensure that the file object is not
// deleted while the I/O operation is in progress. The
// server accomplishes this by incrementing a reference
// count in a local block to account for the I/O; the
// local block in turn references the file object.
// [Context] -- Supplies a PVOID value that is passed to the
// completion routine.
// [FsControlCode] -- Supplies the control code for the operation.
// [MainBuffer] -- Supplies the address of the main buffer. This
// must be a system virtual address, and the buffer must
// be locked in memory. If ControlCode specifies a method
// 0 request, the actual length of the buffer must be the
// greater of InputBufferLength and OutputBufferLength.
// [InputBufferLength] -- Supplies the length of the input buffer.
// [AuxiliaryBuffer] -- Supplies the address of the auxiliary
// buffer. If the control code method is 0, this is a
// buffered I/O buffer, but the data returned by the
// called driver in the system buffer is not
// automatically copied into the auxiliary buffer.
// Instead, the auxiliary data ends up in MainBuffer.
// If the caller wishes the data to be in AuxiliaryBuffer,
// it must copy the data at some point after the
// completion routine runs.
// [CompletionRoutine] -- The IO completion routine.
//
// Returns: PIRP -- Returns a pointer to the constructed IRP. If the Irp
// parameter was not NULL on input, the function return value will
// be the same value (so it is safe to discard the return value in
// this case). It is the responsibility of the calling program to
// deallocate the IRP after the I/O request is complete.
//
// Notes: should we use IoBuildIoControlRequest instead?
//
//--------------------------------------------------------------------
PIRP DnrBuildFsControlRequest ( IN PFILE_OBJECT FileObject OPTIONAL, IN PVOID Context, IN ULONG IoControlCode, IN PVOID MainBuffer, IN ULONG InputBufferLength, IN PVOID AuxiliaryBuffer OPTIONAL, IN ULONG OutputBufferLength, IN PIO_COMPLETION_ROUTINE CompletionRoutine ) { CLONG method; PDEVICE_OBJECT deviceObject; PIRP Irp; PIO_STACK_LOCATION irpSp; const UCHAR MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
ASSERT( MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL );
//
// Get the method with which the buffers are being passed.
//
method = IoControlCode & 3; ASSERT( method == METHOD_BUFFERED );
//
// Allocate an IRP. The stack size is one higher
// than that of the target device, to allow for the caller's
// completion routine.
//
deviceObject = IoGetRelatedDeviceObject( FileObject );
//
// Get the address of the target device object.
//
Irp = IoAllocateIrp( (CCHAR)(deviceObject->StackSize + 1), FALSE ); if ( Irp == NULL ) {
//
// Unable to allocate an IRP. Inform the caller.
//
return NULL; }
Irp->RequestorMode = KernelMode;
Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Get a pointer to the current stack location and fill in the
// device object pointer.
//
IoSetNextIrpStackLocation( Irp );
irpSp = IoGetCurrentIrpStackLocation( Irp ); irpSp->DeviceObject = deviceObject;
//
// Set up the completion routine.
//
IoSetCompletionRoutine( Irp, CompletionRoutine, Context, TRUE, TRUE, TRUE );
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the device I/O control request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
irpSp->MajorFunction = MajorFunction; irpSp->MinorFunction = 0; irpSp->FileObject = FileObject; irpSp->DeviceObject = deviceObject;
//
// Copy the caller's parameters to the service-specific portion of the
// IRP for those parameters that are the same for all three methods.
//
irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
Irp->MdlAddress = NULL; Irp->AssociatedIrp.SystemBuffer = MainBuffer; Irp->UserBuffer = AuxiliaryBuffer;
Irp->Flags = (ULONG)IRP_BUFFERED_IO; if ( ARGUMENT_PRESENT(AuxiliaryBuffer) ) { Irp->Flags |= IRP_INPUT_OPERATION; }
return Irp;
}
//+-------------------------------------------------------------------------
//
// Function: AllocateDnrContext, public
//
// Synopsis: AllocateDnrContext will allocate a DNR_CONTEXT
// record.
//
// Arguments: -none-
//
// Returns: PDNR_CONTEXT - a pointer to the allocated DNR_CONTEXT;
// NULL if not enough memory.
//
// Notes: We should investigate allocating this out of the
// IrpContext Zone if they are similar enough in size.
//
//--------------------------------------------------------------------------
PDNR_CONTEXT AllocateDnrContext( IN ULONG cbExtra ) { PDNR_CONTEXT pNRC;
pNRC = ExAllocatePoolWithTag( NonPagedPool, sizeof (DNR_CONTEXT) + cbExtra, ' puM'); if (pNRC == NULL) { return NULL; } RtlZeroMemory(pNRC, sizeof (DNR_CONTEXT)); pNRC->NodeTypeCode = DSFS_NTC_DNR_CONTEXT; pNRC->NodeByteSize = sizeof (DNR_CONTEXT);
return pNRC; }
//+-------------------------------------------------------------------------
//
// Function: DnrConcatenateFilePath, public
//
// Synopsis: DnrConcatenateFilePath will concatenate two strings
// representing file path names, assuring that they are
// separated by a single '\' character.
//
// Arguments: [Dest] - a pointer to the destination string
// [RemainingPath] - the final part of the path name
// [Length] - the length (in bytes) of RemainingPath
//
// Returns: BOOLEAN - TRUE unless Dest is too small to
// hold the result (assert).
//
//--------------------------------------------------------------------------
BOOLEAN DnrConcatenateFilePath ( IN PUNICODE_STRING Dest, IN PWSTR RemainingPath, IN USHORT Length ) { PWSTR OutBuf = (PWSTR)&(((PCHAR)Dest->Buffer)[Dest->Length]); ULONG NewLen;
if (Dest->Length > 0) { ASSERT(OutBuf[-1] != UNICODE_NULL); }
if (Length == 0) { return TRUE; }
if (Dest->Length > 0 && OutBuf[-1] != UNICODE_PATH_SEP) { *OutBuf++ = UNICODE_PATH_SEP; Dest->Length += sizeof (WCHAR); }
if (Length > 0 && *RemainingPath == UNICODE_PATH_SEP) { RemainingPath++; Length -= sizeof (WCHAR); }
NewLen = (ULONG)Dest->Length + (ULONG)Length;
if (NewLen > MAXUSHORT || NewLen > (ULONG)Dest->MaximumLength) {
return FALSE;
}
if (Length > 0) { RtlMoveMemory(OutBuf, RemainingPath, Length); Dest->Length += Length; } return TRUE; }
//+----------------------------------------------------------------------------
//
// Function: DnrLocateDC, private
//
// Synopsis: Tries to create an entry for the Dfs root which will match
// FileName.
//
// Arguments: [FileName] -- File name for which DC/Root is being located.
//
// Returns: Nothing.
//
//-----------------------------------------------------------------------------
VOID DnrLocateDC( IN PUNICODE_STRING FileName) { BOOLEAN pktLocked; NTSTATUS status; UNICODE_STRING dfsRoot, dfsShare, remPath; UNICODE_STRING RootShareName; PDFS_PKT_ENTRY pktEntry; PDFS_PKT pkt; USHORT i, j;
ASSERT( FileName->Buffer[0] == UNICODE_PATH_SEP );
#if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC(%wZ)\n", FileName); #endif
dfsRoot.Length = dfsRoot.MaximumLength = 0; dfsRoot.Buffer = &FileName->Buffer[1];
for (i = 1; i < FileName->Length/sizeof(WCHAR) && FileName->Buffer[i] != UNICODE_PATH_SEP; i++) {
NOTHING;
}
for (j = i + 1; j < FileName->Length/sizeof(WCHAR) && FileName->Buffer[j] != UNICODE_PATH_SEP; j++) {
NOTHING;
}
if ((FileName->Buffer[i] == UNICODE_PATH_SEP) && (j > i)) {
dfsRoot.MaximumLength = dfsRoot.Length = (i - 1) * sizeof(WCHAR); dfsShare.MaximumLength = dfsShare.Length = (j - i - 1) * sizeof(WCHAR); dfsShare.Buffer = &FileName->Buffer[i+1]; #if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC dfsRoot=[%wZ] dfsShare=[%wZ]\n", &dfsRoot, &dfsShare); #endif
status = PktCreateDomainEntry( &dfsRoot, &dfsShare, FALSE );
if (!NT_SUCCESS(status)) {
#if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC:PktCreateDomainEntry() returned 0x%x\n", status); #endif
RootShareName.Buffer = FileName->Buffer; RootShareName.Length = j * sizeof(WCHAR); RootShareName.MaximumLength = FileName->MaximumLength; #if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC:RootShareName=[%wZ]\n", &RootShareName); #endif
//
// Failed getting referral - see if we have a stale one.
//
pkt = _GetPkt();
PktAcquireShared( TRUE, &pktLocked );
pktEntry = PktLookupEntryByPrefix( pkt, &RootShareName, &remPath );
if (pktEntry != NULL) {
#if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC:Found stale pkt entry %08lx - adding 60 sec to it\n", pktEntry); #endif
if (pktEntry->ExpireTime <= 0) { pktEntry->ExpireTime = 60; pktEntry->TimeToLive = 60; }
status = STATUS_SUCCESS;
}
PktRelease();
}
} else {
status = STATUS_BAD_NETWORK_PATH;
}
#if DBG
if (MupVerbose) DbgPrint(" DnrLocateDC exit 0x%x\n", status); #endif
}
//+----------------------------------------------------------------------------
//
// Function: DnrRebuildDnrContext
//
// Synopsis: To handle inter-dfs links, we simply want to change the name
// of the file we are opening to the name in the new Dfs, and
// restart DNR afresh.
//
// This is most easily done by simply terminating this DNR with
// STATUS_REPARSE. However, if we do that, we would loose track
// of the credentials (if any) we originally came in with.
//
// Hence, this routine simply rebuilds the DnrContext. After
// calling this, Dnr starts all over again, just as if
// DnrNameResolve had been called by DnrStartNameResolution
//
//
// Arguments: [DnrContext] -- The context to rebuild.
// [NewDfsPrefix] -- The prefix of the Dfs in which the DNR
// should continue.
// [RemainingPath] -- Path relative to the NewDfsPrefix.
//
// Returns: Nothing.
//
//-----------------------------------------------------------------------------
VOID DnrRebuildDnrContext( IN PDNR_CONTEXT DnrContext, IN PUNICODE_STRING NewDfsPrefix, IN PUNICODE_STRING RemainingPath) { UNICODE_STRING newFileName; ULONG newNameLen = 0;
PIRP Irp = DnrContext->OriginalIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject;
//
// Build the new file name
//
newFileName.Length = 0;
newNameLen = NewDfsPrefix->Length + sizeof(UNICODE_PATH_SEP) + RemainingPath->Length + sizeof(UNICODE_NULL);
if (newNameLen >= MAXUSHORT) {
DnrContext->FinalStatus = STATUS_NAME_TOO_LONG; DnrContext->State = DnrStateDone; return;
}
newFileName.MaximumLength = (USHORT)newNameLen;
newFileName.Buffer = (PWCHAR) ExAllocatePoolWithTag( NonPagedPool, newFileName.MaximumLength, ' puM');
if (newFileName.Buffer != NULL) {
newFileName.Length = NewDfsPrefix->Length;
RtlMoveMemory( newFileName.Buffer, NewDfsPrefix->Buffer, newFileName.Length);
DnrConcatenateFilePath( &newFileName, RemainingPath->Buffer, RemainingPath->Length);
if (DnrContext->NameAllocated) ExFreePool(DnrContext->FileName.Buffer);
DnrContext->NameAllocated = TRUE;
DnrContext->FileName = newFileName;
} else {
DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
DnrContext->State = DnrStateDone;
return; }
//
// Rebuild the FcbToUse because the Fcb has room for the full file name
// and it might have changed its size.
//
ASSERT(DnrContext->FcbToUse != NULL);
DfsDetachFcb(DnrContext->FcbToUse->FileObject, DnrContext->FcbToUse); ExFreePool(DnrContext->FcbToUse);
DnrContext->FcbToUse = DfsCreateFcb( DnrContext->pIrpContext, DnrContext->Vcb, &DnrContext->ContextFileName);
if (DnrContext->FcbToUse == NULL) {
DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
DnrContext->State = DnrStateDone;
return;
} DnrContext->FcbToUse->FileObject = FileObject; DfsSetFileObject(FileObject, RedirectedFileOpen, DnrContext->FcbToUse);
//
// Now, whack the rest of the DnrContext. Clean it up so it is essentially
// zeroed out..
//
DnrContext->State = DnrStateStart;
DnrContext->pPktEntry = NULL; DnrContext->USN = 0; DnrContext->pService = NULL; DnrContext->pProvider = NULL; DnrContext->ProviderId = 0; DnrContext->TargetDevice = NULL; DnrContext->AuthConn = NULL; DnrContext->DCConnFile = NULL;
DnrContext->ReferralSize = MAX_REFERRAL_LENGTH; DnrContext->Attempts++; DnrContext->GotReferral = FALSE; DnrContext->FoundInconsistency = FALSE; DnrContext->CalledDCLocator = FALSE; DnrContext->CachedConnFile = FALSE; DnrContext->DfsNameContext.Flags = 0; DnrContext->GotReparse = FALSE;
}
//+-------------------------------------------------------------------------
//
// Function: DfspGetOfflineEntry -- Checks for a server marked offline.
//
// Synopsis: DfspGetOfflineEntry returns an offline entry for the given
// server, if it exists in our offline database.
//
// Arguments: [servername] - Name of the server of interest.
// DfsData.Resource assumed held on entry.
//
// Returns: PLIST_ENTRY: plist_entry of the offline structure.
//
//--------------------------------------------------------------------------
PLIST_ENTRY DfspGetOfflineEntry( PUNICODE_STRING ServerName) { PLIST_ENTRY listEntry; PDFS_OFFLINE_SERVER server;
listEntry = DfsData.OfflineRoots.Flink;
while ( listEntry != &DfsData.OfflineRoots ) { server = CONTAINING_RECORD( listEntry, DFS_OFFLINE_SERVER, ListEntry); if (RtlCompareUnicodeString( &server->LogicalServerName, ServerName, TRUE) == 0) { break; } listEntry = listEntry->Flink; } if (listEntry == &DfsData.OfflineRoots) { listEntry = NULL; } return listEntry; }
//+-------------------------------------------------------------------------
//
// Function: DfspMarkServerOnline -- Marks a server online
//
// Synopsis: DfspMarkServerOnline removes the server entry from its offline
// database, if it was marked as offline earlier.
//
// Arguments: [servername] - Name of the server of interest.
//
// Returns: NTSTATUS.
//
//--------------------------------------------------------------------------
NTSTATUS DfspMarkServerOnline( PUNICODE_STRING ServerName) { PLIST_ENTRY listEntry; PDFS_OFFLINE_SERVER server; NTSTATUS status; UNICODE_STRING dfsRootName; ULONG i;
DfsDbgTrace(+1, Dbg, "DfspMarkServerOnline: %wZ\n", ServerName);
//
// Extract server name when there is \server\share
//
dfsRootName = *ServerName; if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) { for (i = 1; i < dfsRootName.Length/sizeof(WCHAR) && dfsRootName.Buffer[i] != UNICODE_PATH_SEP; i++) { NOTHING; } dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR)); dfsRootName.MaximumLength = dfsRootName.Length; dfsRootName.Buffer = &ServerName->Buffer[1]; }
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
listEntry = DfspGetOfflineEntry(&dfsRootName);
if (listEntry != NULL) { RemoveEntryList(listEntry); } ExReleaseResourceLite( &DfsData.Resource );
if (listEntry != NULL) { server = CONTAINING_RECORD( listEntry, DFS_OFFLINE_SERVER, ListEntry); ExFreePool(server->LogicalServerName.Buffer); ExFreePool(server); }
MupInvalidatePrefixTable(); status = STATUS_SUCCESS; DfsDbgTrace(-1, Dbg, "DfspMarkServerOnline: status %x\n", ULongToPtr(status)); return status; }
//+-------------------------------------------------------------------------
//
// Function: DfspMarkServerOffline -- Marks a server offline
//
// Synopsis: DfspMarkServerOffline adds the server entry to its offline
// database.
//
// Arguments: [servername] - Name of the server of interest.
//
// Returns: NTSTATUS.
//
//--------------------------------------------------------------------------
NTSTATUS DfspMarkServerOffline( PUNICODE_STRING ServerName) { UNICODE_STRING NewName; PLIST_ENTRY listEntry; PDFS_OFFLINE_SERVER server; UNICODE_STRING dfsRootName; ULONG i;
DfsDbgTrace(+1, Dbg, "DfspMarkServerOffline: %wZ \n", ServerName);
server = ExAllocatePoolWithTag( PagedPool, sizeof(DFS_OFFLINE_SERVER), ' puM' ); if (server == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
//
// Extract server name when there is \server\share
//
dfsRootName = *ServerName; if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) { for (i = 1; i < dfsRootName.Length/sizeof(WCHAR) && dfsRootName.Buffer[i] != UNICODE_PATH_SEP; i++) { NOTHING; } dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR)); dfsRootName.MaximumLength = dfsRootName.Length; dfsRootName.Buffer = &ServerName->Buffer[1]; }
NewName.Buffer = ExAllocatePoolWithTag( PagedPool, dfsRootName.Length + sizeof(WCHAR), ' puM' );
if (NewName.Buffer == NULL) { ExFreePool(server); return STATUS_INSUFFICIENT_RESOURCES; }
NewName.MaximumLength = dfsRootName.Length + sizeof(WCHAR); NewName.Length = 0;
RtlCopyUnicodeString(&NewName, &dfsRootName);
server->LogicalServerName = NewName;
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
listEntry = DfspGetOfflineEntry(&dfsRootName);
if (listEntry == NULL) { InsertTailList( &DfsData.OfflineRoots, &server->ListEntry); } ExReleaseResourceLite( &DfsData.Resource );
if (listEntry != NULL) { ExFreePool(NewName.Buffer); ExFreePool(server); } DfsDbgTrace(-1, Dbg, "DfspMarkServerOffline exit STATUS_SUCCESS\n", 0); return STATUS_SUCCESS; }
//+-------------------------------------------------------------------------
//
// Function: DfspIsRootOnline -- Checks if a server is online
//
// Synopsis: DfspIsRootOnline checks if the server is marked in its offline
// database. If not, the server is online.
//
// Arguments: [servername] - Name of the server of interest.
//
// Returns: NTSTATUS. (Success or STATUS_DEVICE_OFFLINE)
//
//--------------------------------------------------------------------------
NTSTATUS DfspIsRootOnline( PUNICODE_STRING FileName, BOOLEAN CSCAgentCreate) { NTSTATUS status; PLIST_ENTRY listEntry; UNICODE_STRING dfsRootName; ULONG i;
DfsDbgTrace(+1, Dbg, "DfspIsRootOnline: %wZ\n", FileName);
if (CSCAgentCreate == TRUE) { DfsDbgTrace(-1, Dbg, "CSCAgent, returning success!\n", 0); status = STATUS_SUCCESS; } else { dfsRootName = *FileName; if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) { for (i = 1; i < dfsRootName.Length/sizeof(WCHAR) && dfsRootName.Buffer[i] != UNICODE_PATH_SEP; i++) { NOTHING; } dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR)); dfsRootName.MaximumLength = dfsRootName.Length; dfsRootName.Buffer = &FileName->Buffer[1]; }
ExAcquireResourceSharedLite( &DfsData.Resource, TRUE ); listEntry = DfspGetOfflineEntry(&dfsRootName); ExReleaseResourceLite( &DfsData.Resource );
if (listEntry != NULL) { status = STATUS_DEVICE_OFF_LINE; } else { status = STATUS_SUCCESS; } }
DfsDbgTrace(-1, Dbg, "DfspIsRootOnline: ret 0x%x\n", ULongToPtr(status) );
return status; }
#if 0
NTSTATUS DnrGetTargetInfo( PDNR_CONTEXT pDnrContext) { UNICODE_STRING dfsRoot, dfsShare; PUNICODE_STRING pFileName = &pDnrContext->FileName; USHORT i, j; NTSTATUS Status;
dfsRoot.Length = dfsRoot.MaximumLength = 0; dfsRoot.Buffer = &pFileName->Buffer[1];
for (i = 1; i < pFileName->Length/sizeof(WCHAR) && pFileName->Buffer[i] != UNICODE_PATH_SEP; i++) {
NOTHING;
}
for (j = i + 1; j < pFileName->Length/sizeof(WCHAR) && pFileName->Buffer[j] != UNICODE_PATH_SEP; j++) {
NOTHING;
}
if ((pFileName->Buffer[i] == UNICODE_PATH_SEP) && (j > i)) {
dfsRoot.MaximumLength = dfsRoot.Length = (i - 1) * sizeof(WCHAR); dfsShare.MaximumLength = dfsShare.Length = (j - i - 1) * sizeof(WCHAR); dfsShare.Buffer = &pFileName->Buffer[i+1];
Status = PktGetTargetInfo( pDnrContext->DCConnFile, &dfsRoot, &dfsShare, &pDnrContext->pNewTargetInfo ); } else { Status = STATUS_BAD_NETWORK_PATH; }
return Status; }
#endif
NTSTATUS DnrGetTargetInfo( PDNR_CONTEXT pDnrContext) { NTSTATUS Status = STATUS_SUCCESS; PDFS_PKT_ENTRY pEntry;
pEntry = pDnrContext->pPktEntry; if (pEntry != NULL) { pDnrContext->pNewTargetInfo = pEntry->pDfsTargetInfo; if (pDnrContext->pNewTargetInfo != NULL) { PktAcquireTargetInfo(pDnrContext->pNewTargetInfo); } }
if (pDnrContext->pNewTargetInfo == NULL) { if (pDnrContext->pDfsTargetInfo != NULL) { pDnrContext->pNewTargetInfo = pDnrContext->pDfsTargetInfo; if (pDnrContext->pNewTargetInfo != NULL) { PktAcquireTargetInfo(pDnrContext->pNewTargetInfo); } } }
return Status; }
|