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

1081 lines
36 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Rdbss.
  7. Fsctls on the device fcb are handled in another module.
  8. Author:
  9. Joe Linn [JoeLinn] 7-mar-95
  10. Revision History:
  11. Balan Sethu Raman 18-May-95 -- Integrated with mini rdrs
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <dfsfsctl.h>
  16. #include "fsctlbuf.h"
  17. //
  18. // The local debug trace level
  19. //
  20. #define Dbg (DEBUG_TRACE_FSCTRL)
  21. //
  22. // Local procedure prototypes
  23. //
  24. NTSTATUS
  25. RxUserFsCtrl (
  26. IN PRX_CONTEXT RxContext
  27. );
  28. NTSTATUS
  29. TranslateSisFsctlName (
  30. IN PWCHAR InputName,
  31. OUT PUNICODE_STRING RelativeName,
  32. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  33. IN PUNICODE_STRING NetRootName
  34. );
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGE, RxCommonFileSystemControl)
  37. #pragma alloc_text(PAGE, RxUserFsCtrl)
  38. #pragma alloc_text(PAGE, RxLowIoFsCtlShell)
  39. #pragma alloc_text(PAGE, RxLowIoFsCtlShellCompletion)
  40. #pragma alloc_text(PAGE, TranslateSisFsctlName)
  41. #endif
  42. //
  43. // Global to enable throttling namedpipe peeks
  44. //
  45. ULONG RxEnablePeekBackoff = 1;
  46. NTSTATUS
  47. RxCommonFileSystemControl (
  48. IN PRX_CONTEXT RxContext,
  49. IN PIRP Irp
  50. )
  51. /*++
  52. Routine Description:
  53. This is the common routine for doing FileSystem control operations called
  54. by both the fsd and fsp threads. What happens is that we pick off fsctls that
  55. we know about and remote the rest....remoting means sending them thru the
  56. lowio stuff which may/will pick off a few more. the ones that we pick off here
  57. (and currently return STATUS_NOT_IMPLEMENTED) and the ones for being an oplock
  58. provider and for doing volume mounts....we don't even have volume fcbs
  59. yet since this is primarily a localFS concept.
  60. nevertheless, these are not passed thru to the mini.
  61. Arguments:
  62. Return Value:
  63. NTSTATUS - The return status for the operation
  64. --*/
  65. {
  66. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  67. PFILE_OBJECT FileObject = IrpSp->FileObject;
  68. PFCB Fcb;
  69. PFOBX Fobx;
  70. NTSTATUS Status;
  71. NODE_TYPE_CODE TypeOfOpen;
  72. BOOLEAN TryLowIo = TRUE;
  73. ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  74. PAGED_CODE();
  75. TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  76. RxDbgTrace( +1, Dbg, ("RxCommonFileSystemControl %08lx\n", RxContext) );
  77. RxDbgTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  78. RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) );
  79. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode) );
  80. RxLog(( "FsCtl %x %x %x %x", RxContext, Irp, IrpSp->MinorFunction, FsControlCode ));
  81. RxWmiLog( LOG,
  82. RxCommonFileSystemControl,
  83. LOGPTR( RxContext )
  84. LOGPTR( Irp )
  85. LOGUCHAR( IrpSp->MinorFunction )
  86. LOGULONG( FsControlCode ) );
  87. ASSERT( IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL );
  88. //
  89. // Validate the buffers passed in for the FSCTL
  90. //
  91. if ((Irp->RequestorMode == UserMode) &&
  92. (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP ))) {
  93. try {
  94. switch (FsControlCode & 3) {
  95. case METHOD_NEITHER:
  96. {
  97. PVOID InputBuffer,OutputBuffer;
  98. ULONG InputBufferLength,OutputBufferLength;
  99. Status = STATUS_SUCCESS;
  100. InputBuffer = METHODNEITHER_OriginalInputBuffer( IrpSp );
  101. OutputBuffer = METHODNEITHER_OriginalOutputBuffer( Irp );
  102. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  103. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  104. if (InputBuffer != NULL) {
  105. ProbeForRead( InputBuffer,
  106. InputBufferLength,
  107. 1 );
  108. ProbeForWrite( InputBuffer,
  109. InputBufferLength,
  110. 1 );
  111. } else if (InputBufferLength != 0) {
  112. Status = STATUS_INVALID_USER_BUFFER;
  113. }
  114. if (Status == STATUS_SUCCESS) {
  115. if (OutputBuffer != NULL) {
  116. ProbeForRead( OutputBuffer,
  117. OutputBufferLength,
  118. 1 );
  119. ProbeForWrite( OutputBuffer,
  120. OutputBufferLength,
  121. 1 );
  122. } else if (OutputBufferLength != 0) {
  123. Status = STATUS_INVALID_USER_BUFFER;
  124. }
  125. }
  126. }
  127. break;
  128. case METHOD_BUFFERED:
  129. case METHOD_IN_DIRECT:
  130. case METHOD_OUT_DIRECT:
  131. Status = STATUS_SUCCESS;
  132. break;
  133. }
  134. } except( EXCEPTION_EXECUTE_HANDLER ) {
  135. Status = STATUS_INVALID_USER_BUFFER;
  136. }
  137. if (Status != STATUS_SUCCESS) {
  138. return Status;
  139. }
  140. }
  141. switch (IrpSp->MinorFunction) {
  142. case IRP_MN_USER_FS_REQUEST:
  143. case IRP_MN_TRACK_LINK:
  144. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode) );
  145. switch (FsControlCode) {
  146. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  147. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  148. case FSCTL_REQUEST_BATCH_OPLOCK:
  149. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  150. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  151. case FSCTL_OPLOCK_BREAK_NOTIFY:
  152. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  153. //
  154. // Oplocks are not implemented for remote file systems
  155. //
  156. Status = STATUS_NOT_IMPLEMENTED;
  157. TryLowIo = FALSE;
  158. break;
  159. case FSCTL_LOCK_VOLUME:
  160. case FSCTL_UNLOCK_VOLUME:
  161. case FSCTL_DISMOUNT_VOLUME:
  162. case FSCTL_MARK_VOLUME_DIRTY:
  163. case FSCTL_IS_VOLUME_MOUNTED:
  164. //
  165. // Decode the file object, the only type of opens we accept are
  166. // user volume opens (which are not implemented currently).
  167. //
  168. TypeOfOpen = NodeType( Fcb );
  169. if (TypeOfOpen != RDBSS_NTC_VOLUME_FCB) {
  170. Status = STATUS_INVALID_PARAMETER;
  171. } else {
  172. Status = STATUS_NOT_IMPLEMENTED;
  173. }
  174. TryLowIo = FALSE;
  175. break;
  176. case FSCTL_DFS_GET_REFERRALS:
  177. case FSCTL_DFS_REPORT_INCONSISTENCY:
  178. if (!FlagOn( Fcb->NetRoot->SrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER )) {
  179. TryLowIo = FALSE;
  180. Status = STATUS_DFS_UNAVAILABLE;
  181. }
  182. break;
  183. case FSCTL_LMR_GET_LINK_TRACKING_INFORMATION:
  184. {
  185. //
  186. // Validate the parameters and reject illformed requests
  187. //
  188. ULONG OutputBufferLength;
  189. PLINK_TRACKING_INFORMATION LinkTrackingInformation;
  190. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  191. LinkTrackingInformation = Irp->AssociatedIrp.SystemBuffer;
  192. TryLowIo = FALSE;
  193. if ((OutputBufferLength < sizeof(LINK_TRACKING_INFORMATION)) ||
  194. (LinkTrackingInformation == NULL) ||
  195. (Fcb->NetRoot->Type != NET_ROOT_DISK)) {
  196. Status = STATUS_INVALID_PARAMETER;
  197. } else {
  198. BYTE Buffer[sizeof(FILE_FS_OBJECTID_INFORMATION)];
  199. PFILE_FS_OBJECTID_INFORMATION ObjectIdInfo;
  200. ObjectIdInfo = (PFILE_FS_OBJECTID_INFORMATION)Buffer;
  201. RxContext->Info.FsInformationClass = FileFsObjectIdInformation;
  202. RxContext->Info.Buffer = ObjectIdInfo;
  203. RxContext->Info.LengthRemaining = sizeof( Buffer );
  204. MINIRDR_CALL( Status,
  205. RxContext,
  206. Fcb->MRxDispatch,
  207. MRxQueryVolumeInfo,
  208. (RxContext) );
  209. if ((Status == STATUS_SUCCESS) ||
  210. (Status == STATUS_BUFFER_OVERFLOW)) {
  211. //
  212. // Copy the volume Id onto the net root.
  213. //
  214. RtlCopyMemory( &Fcb->NetRoot->DiskParameters.VolumeId,
  215. ObjectIdInfo->ObjectId,
  216. sizeof( GUID ) );
  217. RtlCopyMemory( LinkTrackingInformation->VolumeId,
  218. &Fcb->NetRoot->DiskParameters.VolumeId,
  219. sizeof( GUID ) );
  220. if (FlagOn( Fcb->NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT )) {
  221. LinkTrackingInformation->Type = DfsLinkTrackingInformation;
  222. } else {
  223. LinkTrackingInformation->Type = NtfsLinkTrackingInformation;
  224. }
  225. Irp->IoStatus.Information = sizeof( LINK_TRACKING_INFORMATION );
  226. Status = STATUS_SUCCESS;
  227. }
  228. }
  229. Irp->IoStatus.Status = Status;
  230. }
  231. break;
  232. case FSCTL_SET_ZERO_DATA:
  233. {
  234. PFILE_ZERO_DATA_INFORMATION ZeroRange;
  235. Status = STATUS_SUCCESS;
  236. //
  237. // Verify if the request is well formed...
  238. // a. check if the input buffer length is OK
  239. //
  240. if (IrpSp->Parameters.FileSystemControl.InputBufferLength <
  241. sizeof( FILE_ZERO_DATA_INFORMATION )) {
  242. Status = STATUS_INVALID_PARAMETER;
  243. } else {
  244. //
  245. // b. Ensure the ZeroRange request is properly formed.
  246. //
  247. ZeroRange = (PFILE_ZERO_DATA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  248. if ((ZeroRange->FileOffset.QuadPart < 0) ||
  249. (ZeroRange->BeyondFinalZero.QuadPart < 0) ||
  250. (ZeroRange->FileOffset.QuadPart > ZeroRange->BeyondFinalZero.QuadPart)) {
  251. Status = STATUS_INVALID_PARAMETER;
  252. }
  253. }
  254. if (Status == STATUS_SUCCESS) {
  255. //
  256. // Before the request can be processed ensure that there
  257. // are no user mapped sections
  258. //
  259. if (!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers, NULL )) {
  260. Status = STATUS_USER_MAPPED_FILE;
  261. }
  262. }
  263. TryLowIo = (Status == STATUS_SUCCESS);
  264. }
  265. break;
  266. case FSCTL_SET_COMPRESSION:
  267. case FSCTL_SET_SPARSE:
  268. //
  269. // Ensure that the close is not delayed is for these FCB's
  270. //
  271. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  272. ASSERT( RxContext != CHANGE_BUFFERING_STATE_CONTEXT );
  273. if ((Status == STATUS_LOCK_NOT_GRANTED) &&
  274. (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT ))) {
  275. RxDbgTrace(0, Dbg, ("Cannot acquire Fcb\n", 0));
  276. RxContext->PostRequest = TRUE;
  277. }
  278. if (Status != STATUS_SUCCESS) {
  279. TryLowIo = FALSE;
  280. } else {
  281. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  282. if (FsControlCode == FSCTL_SET_SPARSE) {
  283. if (NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_FILE) {
  284. SetFlag( Fcb->Attributes, FILE_ATTRIBUTE_SPARSE_FILE );
  285. Fobx->pSrvOpen->BufferingFlags = 0;
  286. //
  287. // disable local buffering
  288. //
  289. SetFlag( Fcb->FcbState, FCB_STATE_DISABLE_LOCAL_BUFFERING );
  290. RxChangeBufferingState( (PSRV_OPEN)Fobx->pSrvOpen,
  291. NULL,
  292. FALSE );
  293. } else {
  294. Status = STATUS_NOT_SUPPORTED;
  295. }
  296. }
  297. RxReleaseFcb( RxContext, Fcb );
  298. }
  299. break;
  300. case IOCTL_LMR_DISABLE_LOCAL_BUFFERING:
  301. if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
  302. //
  303. // Ensure that the close is not delayed is for these FCB's
  304. //
  305. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  306. if ((Status == STATUS_LOCK_NOT_GRANTED) &&
  307. (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT ))) {
  308. RxDbgTrace(0, Dbg, ("Cannot acquire Fcb\n", 0));
  309. RxContext->PostRequest = TRUE;
  310. }
  311. if (Status == STATUS_SUCCESS) {
  312. //
  313. // disable local buffering
  314. //
  315. SetFlag( Fcb->FcbState, FCB_STATE_DISABLE_LOCAL_BUFFERING );
  316. RxChangeBufferingState( Fobx->SrvOpen,
  317. NULL,
  318. FALSE );
  319. RxReleaseFcb( RxContext, Fcb );
  320. }
  321. } else {
  322. Status = STATUS_NOT_SUPPORTED;
  323. }
  324. //
  325. // we are done
  326. //
  327. TryLowIo = FALSE;
  328. break;
  329. case FSCTL_SIS_COPYFILE:
  330. {
  331. //
  332. // This is the single-instance store copy FSCTL. The input
  333. // paths are fully qualified NT paths and must be made
  334. // relative to the share (which must be the same for both
  335. // names).
  336. //
  337. PSI_COPYFILE copyFile = Irp->AssociatedIrp.SystemBuffer;
  338. ULONG bufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  339. PWCHAR source;
  340. PWCHAR dest;
  341. UNICODE_STRING sourceString;
  342. UNICODE_STRING destString;
  343. memset( &sourceString, 0, sizeof( sourceString ) );
  344. memset( &destString, 0, sizeof( destString ) );
  345. //
  346. // Validate the buffer passed in
  347. //
  348. if ((copyFile == NULL) ||
  349. (bufferLength < sizeof( SI_COPYFILE ))) {
  350. Status = STATUS_INVALID_PARAMETER;
  351. TryLowIo = FALSE;
  352. break;
  353. }
  354. //
  355. // Get pointers to the two names.
  356. //
  357. source = copyFile->FileNameBuffer;
  358. dest = source + (copyFile->SourceFileNameLength / sizeof( WCHAR ));
  359. //
  360. // Verify that the inputs are reasonable.
  361. //
  362. if ( (copyFile->SourceFileNameLength > bufferLength) ||
  363. (copyFile->DestinationFileNameLength > bufferLength) ||
  364. (copyFile->SourceFileNameLength < (2 * sizeof(WCHAR))) ||
  365. (copyFile->DestinationFileNameLength < (2 * sizeof(WCHAR))) ||
  366. ((FIELD_OFFSET( SI_COPYFILE, FileNameBuffer ) +
  367. copyFile->SourceFileNameLength +
  368. copyFile->DestinationFileNameLength) > bufferLength) ||
  369. (*(source + (copyFile->SourceFileNameLength/sizeof( WCHAR )-1)) != 0) ||
  370. (*(dest + (copyFile->DestinationFileNameLength/sizeof( WCHAR )-1)) != 0) ) {
  371. Status = STATUS_INVALID_PARAMETER;
  372. TryLowIo = FALSE;
  373. break;
  374. }
  375. //
  376. // Perform symbolic link translation on the source and destination names,
  377. // and ensure that they translate to redirector names.
  378. //
  379. Status = TranslateSisFsctlName( source,
  380. &sourceString,
  381. Fcb->RxDeviceObject,
  382. &Fcb->NetRoot->PrefixEntry.Prefix );
  383. if ( !NT_SUCCESS(Status) ) {
  384. TryLowIo = FALSE;
  385. break;
  386. }
  387. Status = TranslateSisFsctlName( dest,
  388. &destString,
  389. Fcb->RxDeviceObject,
  390. &Fcb->NetRoot->PrefixEntry.Prefix );
  391. if (!NT_SUCCESS( Status )) {
  392. RtlFreeUnicodeString( &sourceString );
  393. TryLowIo = FALSE;
  394. break;
  395. }
  396. //
  397. // Convert the paths in the input buffer into share-relative
  398. // paths.
  399. //
  400. if ( (ULONG)(sourceString.MaximumLength + destString.MaximumLength) >
  401. (copyFile->SourceFileNameLength + copyFile->DestinationFileNameLength) ) {
  402. PSI_COPYFILE newCopyFile;
  403. ULONG length = FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) +
  404. sourceString.MaximumLength + destString.MaximumLength;
  405. ASSERT( length > IrpSp->Parameters.FileSystemControl.InputBufferLength );
  406. newCopyFile = RxAllocatePoolWithTag(
  407. NonPagedPool,
  408. length,
  409. RX_MISC_POOLTAG);
  410. if (newCopyFile == NULL) {
  411. Status = STATUS_INSUFFICIENT_RESOURCES;
  412. TryLowIo = FALSE;
  413. break;
  414. }
  415. newCopyFile->Flags = copyFile->Flags;
  416. ExFreePool( copyFile );
  417. copyFile = newCopyFile;
  418. Irp->AssociatedIrp.SystemBuffer = copyFile;
  419. IrpSp->Parameters.FileSystemControl.InputBufferLength = length;
  420. }
  421. copyFile->SourceFileNameLength = sourceString.MaximumLength;
  422. copyFile->DestinationFileNameLength = destString.MaximumLength;
  423. source = copyFile->FileNameBuffer;
  424. dest = source + (copyFile->SourceFileNameLength / sizeof(WCHAR));
  425. RtlCopyMemory( source, sourceString.Buffer, copyFile->SourceFileNameLength );
  426. RtlCopyMemory( dest, destString.Buffer, copyFile->DestinationFileNameLength );
  427. RtlFreeUnicodeString( &sourceString );
  428. RtlFreeUnicodeString( &destString );
  429. }
  430. break;
  431. default:
  432. break;
  433. }
  434. break;
  435. default:
  436. break;
  437. }
  438. if (TryLowIo) {
  439. Status = RxLowIoFsCtlShell( RxContext, Irp, Fcb, Fobx );
  440. }
  441. if (RxContext->PostRequest) {
  442. Status = RxFsdPostRequest( RxContext );
  443. } else {
  444. if (Status == STATUS_PENDING) {
  445. RxDereferenceAndDeleteRxContext( RxContext );
  446. }
  447. }
  448. RxDbgTrace(-1, Dbg, ("RxCommonFileSystemControl -> %08lx\n", Status));
  449. return Status;
  450. }
  451. NTSTATUS
  452. RxLowIoFsCtlShell (
  453. IN PRX_CONTEXT RxContext,
  454. IN PIRP Irp,
  455. IN PFCB Fcb,
  456. IN PFOBX Fobx
  457. )
  458. /*++
  459. Routine Description:
  460. This is the common routine for implementing the user's requests made
  461. through NtFsControlFile.
  462. Arguments:
  463. Irp - Supplies the Irp being processed
  464. Return Value:
  465. NTSTATUS - The return status for the operation
  466. --*/
  467. {
  468. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  469. PFILE_OBJECT FileObject = IrpSp->FileObject;
  470. NTSTATUS Status = STATUS_SUCCESS;
  471. BOOLEAN PostToFsp = FALSE;
  472. NODE_TYPE_CODE TypeOfOpen = NodeType( Fcb );
  473. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  474. ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  475. BOOLEAN SubmitLowIoRequest = TRUE;
  476. PAGED_CODE();
  477. RxDbgTrace( +1, Dbg, ("RxLowIoFsCtlShell...\n", 0) );
  478. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode));
  479. RxInitializeLowIoContext( RxContext, LOWIO_OP_FSCTL, LowIoContext );
  480. switch (IrpSp->MinorFunction) {
  481. case IRP_MN_USER_FS_REQUEST:
  482. //
  483. // The RDBSS filters out those FsCtls that can be handled without the intervention
  484. // of the mini rdr's. Currently all FsCtls are forwarded down to the mini rdr.
  485. //
  486. switch (FsControlCode) {
  487. case FSCTL_PIPE_PEEK:
  488. if ((Irp->AssociatedIrp.SystemBuffer != NULL) &&
  489. (IrpSp->Parameters.FileSystemControl.OutputBufferLength >=
  490. (ULONG)FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ))) {
  491. PFILE_PIPE_PEEK_BUFFER PeekBuffer = (PFILE_PIPE_PEEK_BUFFER)Irp->AssociatedIrp.SystemBuffer;
  492. RtlZeroMemory( PeekBuffer, IrpSp->Parameters.FileSystemControl.OutputBufferLength );
  493. if (RxShouldRequestBeThrottled( &Fobx->Specific.NamedPipe.ThrottlingState ) &&
  494. RxEnablePeekBackoff) {
  495. SubmitLowIoRequest = FALSE;
  496. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShell: Throttling Peek Request\n") );
  497. Irp->IoStatus.Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER,Data );
  498. PeekBuffer->ReadDataAvailable = 0;
  499. PeekBuffer->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
  500. PeekBuffer->NumberOfMessages = MAXULONG;
  501. PeekBuffer->MessageLength = 0;
  502. RxContext->StoredStatus = STATUS_SUCCESS;
  503. Status = RxContext->StoredStatus;
  504. } else {
  505. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShell: Throttling queries %ld\n", Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries) );
  506. RxLog(( "ThrottlQs %lx %lx %lx %ld\n", RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState, Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  507. RxWmiLog( LOG,
  508. RxLowIoFsCtlShell,
  509. LOGPTR( RxContext )
  510. LOGPTR( Fobx )
  511. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  512. }
  513. } else {
  514. RxContext->StoredStatus = STATUS_INVALID_PARAMETER;
  515. }
  516. break;
  517. default:
  518. break;
  519. }
  520. break;
  521. default:
  522. break;
  523. }
  524. if (SubmitLowIoRequest) {
  525. Status = RxLowIoSubmit( RxContext, Irp, Fcb, RxLowIoFsCtlShellCompletion );
  526. }
  527. RxDbgTrace( -1, Dbg, ("RxLowIoFsCtlShell -> %08lx\n", Status ));
  528. return Status;
  529. }
  530. NTSTATUS
  531. RxLowIoFsCtlShellCompletion (
  532. IN PRX_CONTEXT RxContext
  533. )
  534. /*++
  535. Routine Description:
  536. This is the completion routine for FSCTL requests passed down to the mini rdr
  537. Arguments:
  538. Irp - Supplies the Irp being processed
  539. Return Value:
  540. NTSTATUS - The return status for the operation
  541. --*/
  542. {
  543. PIRP Irp = RxContext->CurrentIrp;
  544. PFCB Fcb = (PFCB)RxContext->pFcb;
  545. PFOBX Fobx = (PFOBX)RxContext->pFobx;
  546. NTSTATUS Status;
  547. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  548. ULONG FsControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode;
  549. PAGED_CODE();
  550. Status = RxContext->StoredStatus;
  551. RxDbgTrace(+1, Dbg, ("RxLowIoFsCtlShellCompletion entry Status = %08lx\n", Status));
  552. switch (FsControlCode) {
  553. case FSCTL_PIPE_PEEK:
  554. if ((Status == STATUS_SUCCESS) || (Status == STATUS_BUFFER_OVERFLOW)) {
  555. //
  556. // In the case of Peek operations a throttle mechanism is in place to
  557. // prevent the network from being flodded with requests which return 0
  558. // bytes.
  559. //
  560. PFILE_PIPE_PEEK_BUFFER PeekBuffer;
  561. PeekBuffer = (PFILE_PIPE_PEEK_BUFFER)LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  562. if (PeekBuffer->ReadDataAvailable == 0) {
  563. //
  564. // The peek request returned zero bytes.
  565. //
  566. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShellCompletion: Enabling Throttling for Peek Request\n") );
  567. RxInitiateOrContinueThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
  568. RxLog(( "ThrottlYes %lx %lx %lx %ld\n", RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState, Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  569. RxWmiLog( LOG,
  570. RxLowIoFsCtlShellCompletion_1,
  571. LOGPTR( RxContext )
  572. LOGPTR( Fobx )
  573. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  574. } else {
  575. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShellCompletion: Disabling Throttling for Peek Request\n" ));
  576. RxTerminateThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
  577. RxLog(( "ThrottlNo %lx %lx %lx %ld\n", RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState, Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  578. RxWmiLog( LOG,
  579. RxLowIoFsCtlShellCompletion_2,
  580. LOGPTR( RxContext )
  581. LOGPTR( Fobx )
  582. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  583. }
  584. Irp->IoStatus.Information = RxContext->InformationToReturn;
  585. }
  586. break;
  587. default:
  588. if ((Status == STATUS_BUFFER_OVERFLOW) || (Status == STATUS_SUCCESS)) {
  589. Irp->IoStatus.Information = RxContext->InformationToReturn;
  590. }
  591. break;
  592. }
  593. Irp->IoStatus.Status = Status;
  594. RxDbgTrace(-1, Dbg, ("RxLowIoFsCtlShellCompletion exit Status = %08lx\n", Status));
  595. return Status;
  596. }
  597. NTSTATUS
  598. TranslateSisFsctlName(
  599. IN PWCHAR InputName,
  600. OUT PUNICODE_STRING RelativeName,
  601. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  602. IN PUNICODE_STRING NetRootName
  603. )
  604. /*++
  605. Routine Description:
  606. This routine converts a fully qualified name into a share-relative name.
  607. It is used to munge the input buffer of the SIS_COPYFILE FSCTL, which
  608. takes two fully qualified NT paths as inputs.
  609. The routine operates by translating the input path as necessary to get
  610. to an actual device name, verifying that the target device is the
  611. redirector, and verifying that the target server/share is the one on
  612. which the I/O was issued.
  613. Arguments:
  614. Return Value:
  615. --*/
  616. {
  617. NTSTATUS Status;
  618. UNICODE_STRING CurrentString;
  619. UNICODE_STRING TestString;
  620. PWCHAR p;
  621. PWCHAR q;
  622. HANDLE Directory;
  623. OBJECT_ATTRIBUTES ObjectAttributes;
  624. PWCHAR translationBuffer = NULL;
  625. ULONG translationLength;
  626. ULONG remainingLength;
  627. ULONG resultLength;
  628. RtlInitUnicodeString( &CurrentString, InputName );
  629. p = CurrentString.Buffer;
  630. if (!p) {
  631. return STATUS_INVALID_PARAMETER;
  632. }
  633. if ((*p == L'\\') && (*(p+1) == L'\\')) {
  634. //
  635. // Special case for name that starts with \\ (i.e., a UNC name):
  636. // assume that the \\ would translate to the redirector's name and
  637. // skip the translation phase.
  638. //
  639. p++;
  640. } else {
  641. //
  642. // The outer loop is executed each time a translation occurs.
  643. //
  644. while ( TRUE ) {
  645. //
  646. // Walk through any directory objects at the beginning of the string.
  647. //
  648. if ( *p != L'\\' ) {
  649. Status = STATUS_OBJECT_NAME_INVALID;
  650. goto error_exit;
  651. }
  652. p++;
  653. //
  654. // The inner loop is executed while walking the directory tree.
  655. //
  656. while ( TRUE ) {
  657. q = wcschr( p, L'\\' );
  658. if ( q == NULL ) {
  659. TestString.Length = CurrentString.Length;
  660. } else {
  661. TestString.Length = (USHORT)(q - CurrentString.Buffer) * sizeof(WCHAR);
  662. }
  663. TestString.Buffer = CurrentString.Buffer;
  664. remainingLength = CurrentString.Length - TestString.Length + sizeof(WCHAR);
  665. InitializeObjectAttributes( &ObjectAttributes,
  666. &TestString,
  667. OBJ_CASE_INSENSITIVE,
  668. NULL,
  669. NULL );
  670. Status = ZwOpenDirectoryObject( &Directory, DIRECTORY_TRAVERSE, &ObjectAttributes );
  671. //
  672. // If we were unable to open the object as a directory, then break out
  673. // of the inner loop and try to open it as a symbolic link.
  674. //
  675. if (!NT_SUCCESS( Status )) {
  676. if (Status != STATUS_OBJECT_TYPE_MISMATCH) {
  677. goto error_exit;
  678. }
  679. break;
  680. }
  681. //
  682. // We opened the directory. Close it and try the next element of the path.
  683. //
  684. ZwClose( Directory );
  685. if (q == NULL) {
  686. //
  687. // The last element of the name is an object directory. Clearly, this
  688. // is not a redirector path.
  689. //
  690. Status = STATUS_OBJECT_TYPE_MISMATCH;
  691. goto error_exit;
  692. }
  693. p = q + 1;
  694. }
  695. //
  696. // Try to open the current name as a symbolic link.
  697. //
  698. Status = ZwOpenSymbolicLinkObject( &Directory, SYMBOLIC_LINK_QUERY, &ObjectAttributes );
  699. //
  700. // If we were unable to open the object as a symbolic link, then break out of
  701. // the outer loop and verify that this is a redirector name.
  702. //
  703. if (!NT_SUCCESS( Status )) {
  704. if (Status != STATUS_OBJECT_TYPE_MISMATCH) {
  705. goto error_exit;
  706. }
  707. break;
  708. }
  709. //
  710. // The object is a symbolic link. Translate it.
  711. //
  712. TestString.MaximumLength = 0;
  713. Status = ZwQuerySymbolicLinkObject( Directory, &TestString, &translationLength );
  714. if (!NT_SUCCESS( Status ) && (Status != STATUS_BUFFER_TOO_SMALL)) {
  715. ZwClose( Directory );
  716. goto error_exit;
  717. }
  718. resultLength = translationLength + remainingLength;
  719. p = RxAllocatePoolWithTag( PagedPool|POOL_COLD_ALLOCATION, resultLength, RX_MISC_POOLTAG );
  720. if (p == NULL) {
  721. Status = STATUS_INSUFFICIENT_RESOURCES;
  722. ZwClose( Directory );
  723. goto error_exit;
  724. }
  725. TestString.MaximumLength = (USHORT)translationLength;
  726. TestString.Buffer = p;
  727. Status = ZwQuerySymbolicLinkObject( Directory, &TestString, NULL );
  728. ZwClose( Directory );
  729. if (!NT_SUCCESS( Status )) {
  730. RxFreePool( p );
  731. goto error_exit;
  732. }
  733. if (TestString.Length > translationLength) {
  734. Status = STATUS_OBJECT_NAME_INVALID;
  735. RxFreePool( p );
  736. goto error_exit;
  737. }
  738. RtlCopyMemory( Add2Ptr( p, TestString.Length ), q, remainingLength );
  739. CurrentString.Buffer = p;
  740. CurrentString.Length = (USHORT)(resultLength - sizeof(WCHAR));
  741. CurrentString.MaximumLength = (USHORT)resultLength;
  742. if (translationBuffer != NULL) {
  743. RxFreePool( translationBuffer );
  744. }
  745. translationBuffer = p;
  746. }
  747. //
  748. // We have a result name. Verify that it is a redirector name.
  749. //
  750. if (!RtlPrefixUnicodeString( &RxDeviceObject->DeviceName, &CurrentString, TRUE )) {
  751. Status = STATUS_OBJECT_NAME_INVALID;
  752. goto error_exit;
  753. }
  754. //
  755. // Skip over the redirector device name.
  756. //
  757. p = Add2Ptr( CurrentString.Buffer, RxDeviceObject->DeviceName.Length / sizeof(WCHAR));
  758. if (*p != L'\\') {
  759. Status = STATUS_OBJECT_NAME_INVALID;
  760. goto error_exit;
  761. }
  762. //
  763. // Skip over the drive letter, if present.
  764. //
  765. if (*(p + 1) == L';') {
  766. p = wcschr( ++p, L'\\' );
  767. if (p == NULL) {
  768. Status = STATUS_OBJECT_NAME_INVALID;
  769. goto error_exit;
  770. }
  771. }
  772. }
  773. //
  774. // Verify that the next part of the string is the correct net root name.
  775. //
  776. CurrentString.Length -= (USHORT)(p - CurrentString.Buffer) * sizeof(WCHAR);
  777. CurrentString.Buffer = p;
  778. if (!RtlPrefixUnicodeString( NetRootName, &CurrentString, TRUE )) {
  779. Status = STATUS_OBJECT_NAME_INVALID;
  780. goto error_exit;
  781. }
  782. p += NetRootName->Length / sizeof( WCHAR );
  783. if (*p != L'\\') {
  784. Status = STATUS_OBJECT_NAME_INVALID;
  785. goto error_exit;
  786. }
  787. p++;
  788. if (*p == 0) {
  789. Status = STATUS_OBJECT_NAME_INVALID;
  790. goto error_exit;
  791. }
  792. //
  793. // Copy the rest of the string after the redirector name to a new buffer.
  794. //
  795. RtlCreateUnicodeString( RelativeName, p );
  796. Status = STATUS_SUCCESS;
  797. error_exit:
  798. if (translationBuffer != NULL) {
  799. RxFreePool( translationBuffer );
  800. }
  801. return Status;
  802. }