/*++ Copyright (c) 1989 Microsoft Corporation Module Name: NtDevFcb.c Abstract: This module implements the FSD level Close, CleanUp, and FsCtl and IoCtl routines for RxDevice files. Also, the createroutine is not here; rather, it is called from CommonCreate and not called directly by the dispatch driver. Each of the pieces listed (close, cleanup, fsctl, ioctl) has its own little section of the file......complete with its own forward-prototypes and alloc pragmas Author: Joe Linn [JoeLinn] 3-aug-1994 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include #include #include "fsctlbuf.h" #include "prefix.h" #include "rxce.h" // // The local trace mask for this part of the module // #define Dbg (DEBUG_TRACE_DEVFCB) NTSTATUS RxXXXControlFileCallthru( IN PRX_CONTEXT RxContext ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxCommonDevFCBFsCtl) #pragma alloc_text(PAGE, RxXXXControlFileCallthru) #pragma alloc_text(PAGE, RxCommonDevFCBClose) #pragma alloc_text(PAGE, RxCommonDevFCBCleanup) #pragma alloc_text(PAGE, RxGetUid) #endif NTSTATUS RxXXXControlFileCallthru( IN PRX_CONTEXT RxContext ) /*++ Routine Description: This routine calls down to the minirdr to implement ioctl and fsctl controls that the wrapper doesn't understand. note that if there is no dispatch defined (i.e. for the wrapper's own device object) then we also set Rxcontext->Fobx to NULL so that the caller won't try to go thru lowio to get to the minirdr. Arguments: RxContext - the context of the request Return Value: RXSTATUS - The FSD status for the request include the PostRequest field.... --*/ { NTSTATUS Status; PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; RxCaptureRequestPacket; PAGED_CODE(); if (RxContext->RxDeviceObject->Dispatch == NULL) { RxContext->pFobx = NULL; //don't try again on lowio return(STATUS_INVALID_DEVICE_REQUEST); } Status = RxLowIoPopulateFsctlInfo (RxContext); if (Status != STATUS_SUCCESS) { return Status; } if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0) && (LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL)) { return STATUS_INVALID_PARAMETER; } if ((LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0) && (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) { return STATUS_INVALID_PARAMETER; } Status = (RxContext->RxDeviceObject->Dispatch->MRxDevFcbXXXControlFile)(RxContext); if (Status!=STATUS_PENDING) { capReqPacket->IoStatus.Information = RxContext->InformationToReturn; } return(Status); } NTSTATUS RxCommonDevFCBClose ( RXCOMMON_SIGNATURE ) /*++ Routine Description: This routine implements the FSD Close for a Device FCB. Arguments: RxDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: RXSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureRequestPacket; RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject; PRX_PREFIX_TABLE pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable; PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxCommonDevFCBClose\n", 0)); RxLog(("DevFcbClose %lx %lx\n",RxContext,capFileObject)); RxWmiLog(LOG, RxCommonDevFCBClose, LOGPTR(RxContext) LOGPTR(capFileObject)); ASSERT (NodeType(capFcb) == RDBSS_NTC_DEVICE_FCB); // deal with the device fcb if (!capFobx) { capFcb->OpenCount--; return STATUS_SUCCESS; } //otherwise, it's a connection-type file. you have to get the lock; then case-out RxAcquirePrefixTableLockExclusive(pRxNetNameTable, TRUE); try { switch (NodeType(capFobx)) { case RDBSS_NTC_V_NETROOT: { PV_NET_ROOT VNetRoot = (PV_NET_ROOT)capFobx; VNetRoot->NumberOfOpens--; RxDereferenceVNetRoot(VNetRoot,LHS_ExclusiveLockHeld); } break; default: Status = STATUS_NOT_IMPLEMENTED; } try_return(NOTHING); //eliminate warning try_exit: NOTHING; } finally { RxReleasePrefixTableLock( pRxNetNameTable ); } return Status; } NTSTATUS RxCommonDevFCBCleanup ( RXCOMMON_SIGNATURE ) /*++ Routine Description: This routine implements the FSD part of closing down a handle to a device FCB. Arguments: RxDeviceObject - Supplies the volume device object where the file being Cleanup exists Irp - Supplies the Irp being processed Return Value: RXSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureRequestPacket; RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject; PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxCommonFCBCleanup\n", 0)); RxLog(("DevFcbCleanup %lx\n",RxContext,capFileObject)); RxWmiLog(LOG, RxCommonDevFCBCleanup, LOGPTR(RxContext) LOGPTR(capFileObject)); ASSERT (NodeType(capFcb) == RDBSS_NTC_DEVICE_FCB); // deal with the device fcb if (!capFobx) { capFcb->UncleanCount--; // RxCompleteContextAndReturn( RxStatus(SUCCESS) ); return STATUS_SUCCESS; } //otherwise, it's a connection-type file. you have to get the lock; then case-out RxAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, TRUE); try { switch (NodeType(capFobx)) { Status = STATUS_SUCCESS; case RDBSS_NTC_V_NETROOT: //nothing to do break; default: Status = STATUS_INVALID_DEVICE_REQUEST; } try_return(NOTHING); //eliminate warning try_exit: NOTHING; } finally { RxReleasePrefixTableLock( RxContext->RxDeviceObject->pRxNetNameTable ); } // RxCompleteContextAndReturn( Status ); return Status; } // | *********************| // | | F S C T L || // | *********************| // NTSTATUS RxCommonDevFCBFsCtl ( RXCOMMON_SIGNATURE ) /*++ Routine Description: This is the common routine for doing FileSystem control operations called by both the fsd and fsp threads Arguments: RxContext - Supplies the Irp to process and stateinfo about where we are Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; RxCaptureRequestPacket; RxCaptureFobx; RxCaptureParamBlock; ULONG FsControlCode = capPARAMS->Parameters.FileSystemControl.FsControlCode; PAGED_CODE(); RxDbgTrace (+1, Dbg, ("RxCommonDevFCBFsCtl IrpC = %08lx\n", RxContext)); RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx, ControlCode = %08lx \n", capPARAMS->MinorFunction, FsControlCode)); RxLog(("DevFcbFsCtl %lx %lx %lx\n",RxContext,capPARAMS->MinorFunction,FsControlCode)); RxWmiLog(LOG, RxCommonDevFCBFsCtl, LOGPTR(RxContext) LOGUCHAR(capPARAMS->MinorFunction) LOGULONG(FsControlCode)); // // We know this is a file system control so we'll case on the // minor function, and call a internal worker routine to complete // the irp. // switch (capPARAMS->MinorFunction) { case IRP_MN_USER_FS_REQUEST: switch (FsControlCode) { #ifdef RDBSSLOG case FSCTL_LMR_DEBUG_TRACE: // // This FSCTL is being disabled since no one uses this anymore. If // it needs to be reactivated for some reason, the appropriate // checks have to be added to make sure that the IRP->UserBuffer is // a valid address. The try/except call below won't protect against // a random kernel address being passed. // return STATUS_INVALID_DEVICE_REQUEST; // the 2nd buffer points to the string // // We need to try/except this call to protect against random buffers // being passed in from UserMode. // try { RxDebugControlCommand(capReqPacket->UserBuffer); } except (EXCEPTION_EXECUTE_HANDLER) { return STATUS_INVALID_USER_BUFFER; } Status = STATUS_SUCCESS; break; #endif //RDBSSLOG default: RxDbgTrace(0, Dbg, ("RxFsdDevFCBFsCTL unknown user request\n")); Status = RxXXXControlFileCallthru(RxContext); if ( (Status == STATUS_INVALID_DEVICE_REQUEST) && (RxContext->pFobx!=NULL) ) { RxDbgTrace(0, Dbg, ("RxCommonDevFCBFsCtl -> Invoking Lowio for FSCTL\n")); Status = RxLowIoFsCtlShell(RxContext); } } break; default : RxDbgTrace(0, Dbg, ("RxFsdDevFCBFsCTL nonuser request!!\n", 0)); Status = RxXXXControlFileCallthru(RxContext); } if (RxContext->PostRequest) { Status = RxFsdPostRequestWithResume(RxContext,RxCommonDevFCBFsCtl); } RxDbgTrace(-1, Dbg, ("RxCommonDevFCBFsCtl -> %08lx\n", Status)); return Status; } // | *********************| // | | I O C T L || // | *********************| #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxCommonDevFCBIoCtl) #endif NTSTATUS RxCommonDevFCBIoCtl ( RXCOMMON_SIGNATURE ) /*++ Routine Description: This is the common routine for doing FileSystem control operations called by both the fsd and fsp threads Arguments: RxContext - Supplies the Irp to process and stateinfo about where we are Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; RxCaptureRequestPacket; RxCaptureFobx; RxCaptureParamBlock; ULONG IoControlCode = capPARAMS->Parameters.DeviceIoControl.IoControlCode; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxCommonDevFCBIoCtl IrpC-%08lx\n", RxContext)); RxDbgTrace( 0, Dbg, ("ControlCode = %08lx\n", IoControlCode)); if (capFobx == NULL) { switch (IoControlCode) { case IOCTL_REDIR_QUERY_PATH: Status = RxPrefixClaim(RxContext); break; default: { Status = RxXXXControlFileCallthru(RxContext); if ((Status != STATUS_PENDING) && RxContext->PostRequest) { Status = RxFsdPostRequestWithResume(RxContext,RxCommonDevFCBIoCtl); } } break; } } else { Status = STATUS_INVALID_HANDLE; } RxDbgTrace(-1, Dbg, ("RxCommonDevFCBIoCtl -> %08lx\n", Status)); return Status; } // // Utility Routine // LUID RxGetUid( IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext ) /*++ Routine Description: This routine gets the effective UID to be used for this create. Arguments: SubjectSecurityContext - Supplies the information from IrpSp. Return Value: None --*/ { LUID LogonId; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxGetUid ... \n", 0)); // Is the thread currently impersonating someone else? if (SubjectSecurityContext->ClientToken != NULL) { // // If its impersonating someone that is logged in locally then use // the local id. // SeQueryAuthenticationIdToken(SubjectSecurityContext->ClientToken, &LogonId); } else { // // Use the processes LogonId // SeQueryAuthenticationIdToken(SubjectSecurityContext->PrimaryToken, &LogonId); } RxDbgTrace(-1, Dbg, (" ->UserUidHigh/Low = %08lx %08lx\n", LogonId.HighPart, LogonId.LowPart)); return LogonId; } // | *********************| // | | V O L I N F O || // | *********************| NTSTATUS RxDevFcbQueryDeviceInfo ( IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp, PFILE_FS_DEVICE_INFORMATION UsersBuffer, ULONG BufferSize, PULONG ReturnedLength ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxCommonDevFCBQueryVolInfo) #pragma alloc_text(PAGE, RxDevFcbQueryDeviceInfo) #endif NTSTATUS RxCommonDevFCBQueryVolInfo ( RXCOMMON_SIGNATURE ) /*++ Routine Description: This is the common routine for doing FileSystem control operations called by both the fsd and fsp threads Arguments: RxContext - Supplies the Irp to process and stateinfo about where we are Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; BOOLEAN PostToFsp = FALSE; RxCaptureRequestPacket; RxCaptureParamBlock; FS_INFORMATION_CLASS InformationClass = capPARAMS->Parameters.QueryVolume.FsInformationClass; PVOID UsersBuffer = capReqPacket->AssociatedIrp.SystemBuffer; ULONG BufferSize = capPARAMS->Parameters.QueryVolume.Length; ULONG ReturnedLength; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxCommonDevFCBQueryVolInfo IrpC-%08lx\n", RxContext)); RxDbgTrace( 0, Dbg, ("ControlCode = %08lx\n", InformationClass)); RxLog(("DevFcbQVolInfo %lx %lx\n",RxContext,InformationClass)); RxWmiLog(LOG, RxCommonDevFCBQueryVolInfo, LOGPTR(RxContext) LOGULONG(InformationClass)); switch (InformationClass) { case FileFsDeviceInformation: Status = RxDevFcbQueryDeviceInfo (RxContext, &PostToFsp, UsersBuffer, BufferSize, &ReturnedLength); break; default: Status = STATUS_NOT_IMPLEMENTED; }; RxDbgTrace(-1, Dbg, ("RxCommonDevFCBQueryVolInfo -> %08lx\n", Status)); if ( PostToFsp ) return RxFsdPostRequestWithResume(RxContext,RxCommonDevFCBQueryVolInfo); if (Status==STATUS_SUCCESS) { capReqPacket->IoStatus.Information = ReturnedLength; } // RxCompleteContextAndReturn( Status ); return Status; } NTSTATUS RxDevFcbQueryDeviceInfo ( IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp, PFILE_FS_DEVICE_INFORMATION UsersBuffer, ULONG BufferSize, PULONG ReturnedLength ) /*++ Routine Description: This routine shuts down up the RDBSS filesystem...i.e. we connect to the MUP. We can only shut down if there's no netroots and if there's only one deviceFCB handle. Arguments: IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers Return Value: RXSTATUS --*/ { NTSTATUS Status; RxCaptureFobx; BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP); PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxDevFcbQueryDeviceInfo -> %08lx\n", 0)); if (BufferSize < sizeof(FILE_FS_DEVICE_INFORMATION)) { return STATUS_BUFFER_OVERFLOW; }; UsersBuffer->Characteristics = FILE_REMOTE_DEVICE; *ReturnedLength = sizeof(FILE_FS_DEVICE_INFORMATION); // deal with the device fcb if (!capFobx) { UsersBuffer->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; return(STATUS_SUCCESS); } //otherwise, it's a connection-type file. you have to get the lock; then case-out if (!RxAcquirePrefixTableLockShared(RxContext->RxDeviceObject->pRxNetNameTable, Wait)) { *PostToFsp = TRUE; return STATUS_PENDING; } try { Status = STATUS_SUCCESS; switch (NodeType(capFobx)) { case RDBSS_NTC_V_NETROOT: { PV_NET_ROOT VNetRoot = (PV_NET_ROOT)capFobx; PNET_ROOT NetRoot = (PNET_ROOT)VNetRoot->NetRoot; if (NetRoot->Type==NET_ROOT_PIPE) { NetRoot->DeviceType = RxDeviceType(NAMED_PIPE); } UsersBuffer->DeviceType = NetRoot->DeviceType; } break; default: Status = STATUS_NOT_IMPLEMENTED; } try_return(NOTHING); //eliminate warning try_exit: NOTHING; } finally { RxReleasePrefixTableLock( RxContext->RxDeviceObject->pRxNetNameTable ); } return Status; }