Source code of Windows XP (NT5)
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.

3064 lines
76 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbpipe.c
  5. Abstract:
  6. This module contains the code for handling named pipe based transact
  7. SMB's.
  8. Functions that are handled are:
  9. SrvCallNamedPipe
  10. SrvWaitNamedPipe
  11. SrvQueryInfoNamedPipe
  12. SrvQueryStateNamedPipe
  13. SrvSetStateNamedPipe
  14. SrvPeekNamedPipe
  15. SrvTransactNamedPipe
  16. Author:
  17. Manny Weiser (9-18-90)
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #include "pipe.tmh"
  22. #pragma hdrstop
  23. #define BugCheckFileId SRV_FILE_PIPE
  24. STATIC
  25. VOID SRVFASTCALL
  26. RestartCallNamedPipe (
  27. IN OUT PWORK_CONTEXT WorkContext
  28. );
  29. STATIC
  30. VOID SRVFASTCALL
  31. RestartWaitNamedPipe (
  32. IN OUT PWORK_CONTEXT WorkContext
  33. );
  34. STATIC
  35. VOID SRVFASTCALL
  36. RestartPeekNamedPipe (
  37. IN OUT PWORK_CONTEXT WorkContext
  38. );
  39. VOID SRVFASTCALL
  40. RestartRawWriteNamedPipe (
  41. IN OUT PWORK_CONTEXT WorkContext
  42. );
  43. STATIC
  44. VOID SRVFASTCALL
  45. RestartTransactNamedPipe (
  46. IN OUT PWORK_CONTEXT WorkContext
  47. );
  48. NTSTATUS
  49. RestartFastTransactNamedPipe (
  50. IN PDEVICE_OBJECT DeviceObject,
  51. IN PIRP Irp,
  52. IN OUT PWORK_CONTEXT WorkContext
  53. );
  54. VOID SRVFASTCALL
  55. RestartFastTransactNamedPipe2 (
  56. IN OUT PWORK_CONTEXT WorkContext
  57. );
  58. VOID SRVFASTCALL
  59. RestartReadNamedPipe (
  60. IN OUT PWORK_CONTEXT WorkContext
  61. );
  62. VOID SRVFASTCALL
  63. RestartWriteNamedPipe (
  64. IN OUT PWORK_CONTEXT WorkContext
  65. );
  66. #ifdef ALLOC_PRAGMA
  67. #pragma alloc_text( PAGE, SrvCallNamedPipe )
  68. #pragma alloc_text( PAGE, SrvWaitNamedPipe )
  69. #pragma alloc_text( PAGE, SrvQueryStateNamedPipe )
  70. #pragma alloc_text( PAGE, SrvQueryInformationNamedPipe )
  71. #pragma alloc_text( PAGE, SrvSetStateNamedPipe )
  72. #pragma alloc_text( PAGE, SrvPeekNamedPipe )
  73. #pragma alloc_text( PAGE, SrvTransactNamedPipe )
  74. #pragma alloc_text( PAGE, SrvFastTransactNamedPipe )
  75. #pragma alloc_text( PAGE, SrvRawWriteNamedPipe )
  76. #pragma alloc_text( PAGE, SrvReadNamedPipe )
  77. #pragma alloc_text( PAGE, SrvWriteNamedPipe )
  78. #pragma alloc_text( PAGE, RestartCallNamedPipe )
  79. #pragma alloc_text( PAGE, RestartWaitNamedPipe )
  80. #pragma alloc_text( PAGE, RestartPeekNamedPipe )
  81. #pragma alloc_text( PAGE, RestartReadNamedPipe )
  82. #pragma alloc_text( PAGE, RestartTransactNamedPipe )
  83. #pragma alloc_text( PAGE, RestartRawWriteNamedPipe )
  84. #pragma alloc_text( PAGE, RestartFastTransactNamedPipe2 )
  85. #pragma alloc_text( PAGE, RestartWriteNamedPipe )
  86. #pragma alloc_text( PAGE8FIL, RestartFastTransactNamedPipe )
  87. #endif
  88. SMB_TRANS_STATUS
  89. SrvCallNamedPipe (
  90. IN OUT PWORK_CONTEXT WorkContext
  91. )
  92. /*++
  93. Routine Description:
  94. This function processes a Call Named pipe request from a
  95. Transaction SMB. This call is handled asynchronously and
  96. is completed in RestartCallNamedPipe.
  97. Arguments:
  98. WorkContext - A pointer to a WORK_CONTEXT block.
  99. Return Value:
  100. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  101. smbtypes.h for a more complete description.
  102. --*/
  103. {
  104. HANDLE fileHandle;
  105. IO_STATUS_BLOCK ioStatusBlock;
  106. OBJECT_ATTRIBUTES objectAttributes;
  107. PFILE_OBJECT fileObject;
  108. OBJECT_HANDLE_INFORMATION handleInformation;
  109. PTRANSACTION transaction;
  110. NTSTATUS status;
  111. UNICODE_STRING pipePath;
  112. UNICODE_STRING fullName;
  113. FILE_PIPE_INFORMATION pipeInformation;
  114. PIRP irp = WorkContext->Irp;
  115. PIO_STACK_LOCATION irpSp;
  116. PAGED_CODE( );
  117. //
  118. // Strip "\PIPE\" prefix from the path string.
  119. //
  120. pipePath = WorkContext->Parameters.Transaction->TransactionName;
  121. if ( pipePath.Length <=
  122. (UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) ) {
  123. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  124. return SmbTransStatusErrorWithoutData;
  125. }
  126. pipePath.Buffer +=
  127. (UNICODE_SMB_PIPE_PREFIX_LENGTH / sizeof(WCHAR)) + 1;
  128. pipePath.Length -= UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR);
  129. //
  130. // Attempt to open the named pipe.
  131. //
  132. SrvAllocateAndBuildPathName(
  133. &SrvNamedPipeRootDirectory,
  134. &pipePath,
  135. NULL,
  136. &fullName
  137. );
  138. if ( fullName.Buffer == NULL ) {
  139. //
  140. // Unable to allocate heap for the full name.
  141. //
  142. IF_DEBUG(ERRORS) {
  143. SrvPrint0( "SrvCallNamedPipe: Unable to allocate heap for full path name\n" );
  144. }
  145. SrvSetSmbError (WorkContext, STATUS_INSUFF_SERVER_RESOURCES);
  146. IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
  147. return SmbTransStatusErrorWithoutData;
  148. }
  149. SrvInitializeObjectAttributes_U(
  150. &objectAttributes,
  151. &fullName,
  152. OBJ_CASE_INSENSITIVE,
  153. NULL,
  154. NULL
  155. );
  156. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  157. status = SrvIoCreateFile(
  158. WorkContext,
  159. &fileHandle,
  160. GENERIC_READ | GENERIC_WRITE,
  161. &objectAttributes,
  162. &ioStatusBlock,
  163. NULL,
  164. FILE_ATTRIBUTE_NORMAL,
  165. FILE_SHARE_READ | FILE_SHARE_WRITE,
  166. FILE_OPEN,
  167. 0, // Create Options
  168. NULL, // EA Buffer
  169. 0, // EA Length
  170. CreateFileTypeNone,
  171. (PVOID)NULL, // Create parameters
  172. IO_FORCE_ACCESS_CHECK,
  173. NULL
  174. );
  175. FREE_HEAP( fullName.Buffer );
  176. //
  177. // If the user didn't have this permission, update the statistics
  178. // database.
  179. //
  180. if ( status == STATUS_ACCESS_DENIED ) {
  181. SrvStatistics.AccessPermissionErrors++;
  182. }
  183. if (!NT_SUCCESS(status)) {
  184. //
  185. // The server could not open the requested name pipe,
  186. // return the error.
  187. //
  188. IF_SMB_DEBUG(OPEN_CLOSE1) {
  189. SrvPrint2( "SrvCallNamedPipe: Failed to open %ws, err=%x\n",
  190. WorkContext->Parameters.Transaction->TransactionName.Buffer, status );
  191. }
  192. SrvSetSmbError (WorkContext, status);
  193. IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
  194. return SmbTransStatusErrorWithoutData;
  195. }
  196. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 15, 0 );
  197. SrvStatistics.TotalFilesOpened++;
  198. //
  199. // Get a pointer to the file object, so that we can directly
  200. // build IRPs for asynchronous operations (read and write).
  201. // Also, get the granted access mask, so that we can prevent the
  202. // client from doing things that it isn't allowed to do.
  203. //
  204. status = ObReferenceObjectByHandle(
  205. fileHandle,
  206. 0,
  207. NULL,
  208. KernelMode,
  209. (PVOID *)&fileObject,
  210. &handleInformation
  211. );
  212. if ( !NT_SUCCESS(status) ) {
  213. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  214. //
  215. // This internal error bugchecks the system.
  216. //
  217. INTERNAL_ERROR(
  218. ERROR_LEVEL_IMPOSSIBLE,
  219. "SrvCallNamedPipe: unable to reference file handle 0x%lx",
  220. fileHandle,
  221. NULL
  222. );
  223. SrvSetSmbError( WorkContext, status );
  224. IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
  225. return SmbTransStatusErrorWithoutData;
  226. }
  227. //
  228. // Save file handle for the completion routine.
  229. //
  230. transaction = WorkContext->Parameters.Transaction;
  231. transaction->FileHandle = fileHandle;
  232. transaction->FileObject = fileObject;
  233. //
  234. // Set the pipe to message mode, so that we can preform a transceive
  235. //
  236. pipeInformation.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
  237. pipeInformation.ReadMode = FILE_PIPE_MESSAGE_MODE;
  238. status = NtSetInformationFile (
  239. fileHandle,
  240. &ioStatusBlock,
  241. (PVOID)&pipeInformation,
  242. sizeof(pipeInformation),
  243. FilePipeInformation
  244. );
  245. if ( !NT_SUCCESS(status) ) {
  246. INTERNAL_ERROR(
  247. ERROR_LEVEL_UNEXPECTED,
  248. "SrvCallNamedPipe: NtSetInformationFile (pipe information) "
  249. "returned %X",
  250. status,
  251. NULL
  252. );
  253. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  254. SrvSetSmbError( WorkContext, status );
  255. IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
  256. return SmbTransStatusErrorWithoutData;
  257. }
  258. //
  259. // Set the Restart Routine addresses in the work context block.
  260. //
  261. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  262. WorkContext->FspRestartRoutine = RestartCallNamedPipe;
  263. transaction = WorkContext->Parameters.Transaction;
  264. //
  265. // Build the IRP to start a pipe transceive.
  266. // Pass this request to NPFS.
  267. //
  268. //
  269. // Inline SrvBuildIoControlRequest
  270. //
  271. {
  272. //
  273. // Get a pointer to the next stack location. This one is used to
  274. // hold the parameters for the device I/O control request.
  275. //
  276. irpSp = IoGetNextIrpStackLocation( irp );
  277. //
  278. // Set up the completion routine.
  279. //
  280. IoSetCompletionRoutine(
  281. irp,
  282. SrvFsdIoCompletionRoutine,
  283. (PVOID)WorkContext,
  284. TRUE,
  285. TRUE,
  286. TRUE
  287. );
  288. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  289. irpSp->MinorFunction = 0;
  290. irpSp->DeviceObject = IoGetRelatedDeviceObject(fileObject);
  291. irpSp->FileObject = fileObject;
  292. irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
  293. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  294. DEBUG irp->RequestorMode = KernelMode;
  295. irp->MdlAddress = NULL;
  296. irp->AssociatedIrp.SystemBuffer = transaction->OutData;
  297. irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  298. transaction->InData;
  299. //
  300. // Copy the caller's parameters to the service-specific portion of the
  301. // IRP for those parameters that are the same for all three methods.
  302. //
  303. irpSp->Parameters.FileSystemControl.OutputBufferLength =
  304. transaction->MaxDataCount;
  305. irpSp->Parameters.FileSystemControl.InputBufferLength =
  306. transaction->DataCount;
  307. irpSp->Parameters.FileSystemControl.FsControlCode =
  308. FSCTL_PIPE_INTERNAL_TRANSCEIVE;
  309. }
  310. (VOID)IoCallDriver(
  311. irpSp->DeviceObject,
  312. irp
  313. );
  314. //
  315. // The tranceive was successfully started. Return the InProgress
  316. // status to the caller, indicating that the caller should do
  317. // nothing further with the SMB/WorkContext at the present time.
  318. //
  319. IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
  320. return SmbTransStatusInProgress;
  321. } // SrvCallNamedPipe
  322. SMB_TRANS_STATUS
  323. SrvWaitNamedPipe (
  324. IN OUT PWORK_CONTEXT WorkContext
  325. )
  326. /*++
  327. Routine Description:
  328. This function processes a Wait named pipe transaction SMB.
  329. It issues an asynchronous call to NPFS. The function
  330. completetion is handled by RestartWaitNamedPipe().
  331. Arguments:
  332. WorkContext - A pointer to a WORK_CONTEXT block.
  333. Return Value:
  334. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  335. smbtypes.h for a more complete description.
  336. --*/
  337. {
  338. PFILE_PIPE_WAIT_FOR_BUFFER pipeWaitBuffer;
  339. PREQ_TRANSACTION request;
  340. PTRANSACTION transaction;
  341. UNICODE_STRING pipePath;
  342. CLONG nameLength;
  343. PAGED_CODE( );
  344. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  345. transaction = WorkContext->Parameters.Transaction;
  346. //
  347. // Allocate and fill in FILE_PIPE_WAIT_FOR_BUFFER structure.
  348. //
  349. pipePath = transaction->TransactionName;
  350. if ( pipePath.Length <= (UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) ) {
  351. //
  352. // The transaction name does not include a pipe name. It's
  353. // either \PIPE or \PIPE\, or it doesn't even have \PIPE.
  354. //
  355. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  356. return SmbTransStatusErrorWithoutData;
  357. }
  358. nameLength = pipePath.Length -
  359. (UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) +
  360. sizeof(WCHAR);
  361. pipeWaitBuffer = ALLOCATE_NONPAGED_POOL(
  362. sizeof(FILE_PIPE_WAIT_FOR_BUFFER) + nameLength,
  363. BlockTypeDataBuffer
  364. );
  365. if ( pipeWaitBuffer == NULL ) {
  366. //
  367. // We could not allocate space for the buffer to issue the
  368. // pipe wait. Fail the request.
  369. //
  370. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  371. IF_DEBUG(TRACE2) SrvPrint0( "SrvWaitNamedPipe complete\n" );
  372. return SmbTransStatusErrorWithoutData;
  373. }
  374. //
  375. // Copy the pipe name not including "\PIPE\" to the pipe wait for
  376. // buffer.
  377. //
  378. pipeWaitBuffer->NameLength = nameLength - sizeof(WCHAR);
  379. RtlCopyMemory(
  380. pipeWaitBuffer->Name,
  381. (PUCHAR)pipePath.Buffer + UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR),
  382. nameLength
  383. );
  384. //
  385. // Fill in the pipe timeout value if necessary.
  386. //
  387. if ( SmbGetUlong( &request->Timeout ) == 0 ) {
  388. pipeWaitBuffer->TimeoutSpecified = FALSE;
  389. } else {
  390. pipeWaitBuffer->TimeoutSpecified = TRUE;
  391. //
  392. // Convert timeout time from milliseconds to NT relative time.
  393. //
  394. pipeWaitBuffer->Timeout.QuadPart = -1 *
  395. UInt32x32To64( SmbGetUlong( &request->Timeout ), 10*1000 );
  396. }
  397. //
  398. // Set the Restart Routine addresses in the work context block.
  399. //
  400. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  401. WorkContext->FspRestartRoutine = RestartWaitNamedPipe;
  402. //
  403. // Build a Wait named pipe IRP and pass the request to NPFS.
  404. //
  405. SrvBuildIoControlRequest(
  406. WorkContext->Irp,
  407. SrvNamedPipeFileObject,
  408. WorkContext,
  409. IRP_MJ_FILE_SYSTEM_CONTROL,
  410. FSCTL_PIPE_WAIT,
  411. pipeWaitBuffer,
  412. sizeof(*pipeWaitBuffer) + nameLength,
  413. NULL,
  414. 0,
  415. NULL,
  416. NULL
  417. );
  418. (VOID)IoCallDriver( SrvNamedPipeDeviceObject, WorkContext->Irp );
  419. //
  420. // The tranceive was successfully started. Return the InProgress
  421. // status to the caller, indicating that the caller should do
  422. // nothing further with the SMB/WorkContext at the present time.
  423. //
  424. IF_DEBUG(TRACE2) SrvPrint0( "SrvWaitNamedPipe complete\n" );
  425. return SmbTransStatusInProgress;
  426. } // SrvWaitNamedPipe
  427. SMB_TRANS_STATUS
  428. SrvQueryStateNamedPipe (
  429. IN OUT PWORK_CONTEXT WorkContext
  430. )
  431. /*++
  432. Routine Description:
  433. This function processes a Query Named pipe transaction SMB.
  434. Since this call cannot block it is handled synchronously.
  435. Arguments:
  436. WorkContext - A pointer to a WORK_CONTEXT block.
  437. Return Value:
  438. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  439. smbtypes.h for a more complete description.
  440. --*/
  441. {
  442. PREQ_TRANSACTION request;
  443. PTRANSACTION transaction;
  444. HANDLE pipeHandle;
  445. IO_STATUS_BLOCK ioStatusBlock;
  446. USHORT pipeHandleState;
  447. FILE_PIPE_INFORMATION pipeInformation;
  448. FILE_PIPE_LOCAL_INFORMATION pipeLocalInformation;
  449. NTSTATUS status;
  450. USHORT fid;
  451. PRFCB rfcb;
  452. PAGED_CODE( );
  453. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  454. transaction = WorkContext->Parameters.Transaction;
  455. //
  456. // Get the FID from the second setup word and use it to generate a
  457. // pointer to the RFCB.
  458. //
  459. // SrvVerifyFid will fill in WorkContext->Rfcb.
  460. //
  461. fid = SmbGetUshort( &transaction->InSetup[1] );
  462. rfcb = SrvVerifyFid(
  463. WorkContext,
  464. fid,
  465. FALSE,
  466. NULL, // don't serialize with raw write
  467. &status
  468. );
  469. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  470. //
  471. // Invalid file ID. Reject the request.
  472. //
  473. IF_DEBUG(SMB_ERRORS) {
  474. SrvPrint1( "SrvQueryStateNamedPipe: Invalid FID: 0x%lx\n", fid );
  475. }
  476. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  477. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
  478. return SmbTransStatusErrorWithoutData;
  479. }
  480. pipeHandle = rfcb->Lfcb->FileHandle;
  481. status = NtQueryInformationFile (
  482. pipeHandle,
  483. &ioStatusBlock,
  484. (PVOID)&pipeInformation,
  485. sizeof(pipeInformation),
  486. FilePipeInformation
  487. );
  488. if (!NT_SUCCESS(status)) {
  489. INTERNAL_ERROR(
  490. ERROR_LEVEL_UNEXPECTED,
  491. "SrvQueryStateNamedPipe: NtQueryInformationFile (pipe "
  492. "information) returned %X",
  493. status,
  494. NULL
  495. );
  496. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  497. SrvSetSmbError( WorkContext, status );
  498. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
  499. return SmbTransStatusErrorWithoutData;
  500. }
  501. status = NtQueryInformationFile (
  502. pipeHandle,
  503. &ioStatusBlock,
  504. (PVOID)&pipeLocalInformation,
  505. sizeof(pipeLocalInformation),
  506. FilePipeLocalInformation
  507. );
  508. if (!NT_SUCCESS(status)) {
  509. INTERNAL_ERROR(
  510. ERROR_LEVEL_UNEXPECTED,
  511. "SrvQueryStateNamedPipe: NtQueryInformationFile (pipe local "
  512. "information) returned %X",
  513. status,
  514. NULL
  515. );
  516. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  517. SrvSetSmbError( WorkContext, status );
  518. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
  519. return SmbTransStatusErrorWithoutData;
  520. }
  521. //
  522. // Query succeeded generate response
  523. //
  524. pipeHandleState = (USHORT)pipeInformation.CompletionMode
  525. << PIPE_COMPLETION_MODE_BITS;
  526. pipeHandleState |= (USHORT)pipeLocalInformation.NamedPipeEnd
  527. << PIPE_PIPE_END_BITS;
  528. pipeHandleState |= (USHORT)pipeLocalInformation.NamedPipeType
  529. << PIPE_PIPE_TYPE_BITS;
  530. pipeHandleState |= (USHORT)pipeInformation.ReadMode
  531. << PIPE_READ_MODE_BITS;
  532. pipeHandleState |= (USHORT)((pipeLocalInformation.MaximumInstances
  533. << PIPE_MAXIMUM_INSTANCES_BITS)
  534. & SMB_PIPE_UNLIMITED_INSTANCES);
  535. SmbPutUshort(
  536. (PSMB_USHORT)WorkContext->Parameters.Transaction->OutParameters,
  537. pipeHandleState
  538. );
  539. transaction->SetupCount = 0;
  540. transaction->ParameterCount = sizeof(pipeHandleState);
  541. transaction->DataCount = 0;
  542. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
  543. return SmbTransStatusSuccess;
  544. } // SrvQueryStateNamedPipe
  545. SMB_TRANS_STATUS
  546. SrvQueryInformationNamedPipe (
  547. IN OUT PWORK_CONTEXT WorkContext
  548. )
  549. /*++
  550. Routine Description:
  551. This function process a Query named pipe information transaction
  552. SMB. This call is handled synchronously.
  553. Arguments:
  554. WorkContext - A pointer to a WORK_CONTEXT block.
  555. Return Value:
  556. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  557. smbtypes.h for a more complete description.
  558. --*/
  559. {
  560. PREQ_TRANSACTION request;
  561. PTRANSACTION transaction;
  562. HANDLE pipeHandle;
  563. IO_STATUS_BLOCK ioStatusBlock;
  564. FILE_PIPE_LOCAL_INFORMATION pipeLocalInformation;
  565. PNAMED_PIPE_INFORMATION_1 namedPipeInfo;
  566. NTSTATUS status;
  567. USHORT fid;
  568. PRFCB rfcb;
  569. PLFCB lfcb;
  570. USHORT level;
  571. CLONG smbPathLength;
  572. PUNICODE_STRING pipeName;
  573. CLONG actualDataSize;
  574. BOOLEAN returnPipeName;
  575. BOOLEAN isUnicode;
  576. PAGED_CODE( );
  577. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  578. transaction = WorkContext->Parameters.Transaction;
  579. //
  580. // Get the FID from the second setup word and use it to generate a
  581. // pointer to the RFCB.
  582. //
  583. // SrvVerifyFid will fill in WorkContext->Rfcb.
  584. //
  585. fid = SmbGetUshort( &transaction->InSetup[1] );
  586. rfcb = SrvVerifyFid(
  587. WorkContext,
  588. fid,
  589. FALSE,
  590. NULL, // don't serialize with raw write
  591. &status
  592. );
  593. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  594. //
  595. // Invalid file ID. Reject the request.
  596. //
  597. IF_DEBUG(SMB_ERRORS) {
  598. SrvPrint1( "SrvQueryStateNamedPipe: Invalid FID: 0x%lx\n", fid );
  599. }
  600. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  601. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
  602. return SmbTransStatusErrorWithoutData;
  603. }
  604. lfcb = rfcb->Lfcb;
  605. pipeHandle = lfcb->FileHandle;
  606. //
  607. // The information level is stored in paramter byte one.
  608. // Verify that is set correctly.
  609. //
  610. level = SmbGetUshort( (PSMB_USHORT)transaction->InParameters );
  611. if ( level != 1 ) {
  612. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  613. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
  614. return SmbTransStatusErrorWithoutData;
  615. }
  616. //
  617. // Now check that the response will fit. If everything expect for
  618. // the pipe name fits, return STATUS_BUFFER_OVERFLOW with the
  619. // fixed size portion of the data.
  620. //
  621. // *** Note that Unicode strings must be aligned in the SMB.
  622. //
  623. pipeName = &lfcb->Mfcb->FileName;
  624. actualDataSize = sizeof(NAMED_PIPE_INFORMATION_1) - sizeof(UCHAR);
  625. isUnicode = SMB_IS_UNICODE( WorkContext );
  626. if ( isUnicode ) {
  627. ASSERT( sizeof(WCHAR) == 2 );
  628. actualDataSize = (actualDataSize + 1) & ~1; // align to SHORT
  629. smbPathLength = (CLONG)(pipeName->Length) + sizeof(WCHAR);
  630. } else {
  631. smbPathLength = (CLONG)(RtlUnicodeStringToOemSize( pipeName ));
  632. }
  633. actualDataSize += smbPathLength;
  634. if ( transaction->MaxDataCount <
  635. FIELD_OFFSET(NAMED_PIPE_INFORMATION_1, PipeName ) ) {
  636. SrvSetSmbError( WorkContext, STATUS_BUFFER_TOO_SMALL );
  637. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
  638. return SmbTransStatusErrorWithoutData;
  639. }
  640. if ( (transaction->MaxDataCount < actualDataSize) ||
  641. (smbPathLength >= MAXIMUM_FILENAME_LENGTH) ) {
  642. //
  643. // Do not return the pipe name. It won't fit in the return buffer.
  644. //
  645. returnPipeName = FALSE;
  646. } else {
  647. returnPipeName = TRUE;
  648. }
  649. //
  650. // Everything is correct, ask NPFS for the information.
  651. //
  652. status = NtQueryInformationFile (
  653. pipeHandle,
  654. &ioStatusBlock,
  655. (PVOID)&pipeLocalInformation,
  656. sizeof(pipeLocalInformation),
  657. FilePipeLocalInformation
  658. );
  659. if (!NT_SUCCESS(status)) {
  660. INTERNAL_ERROR(
  661. ERROR_LEVEL_UNEXPECTED,
  662. "SrvQueryInformationNamedPipe: NtQueryInformationFile (pipe "
  663. "information) returned %X",
  664. status,
  665. NULL
  666. );
  667. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  668. SrvSetSmbError( WorkContext, status );
  669. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
  670. return SmbTransStatusErrorWithoutData;
  671. }
  672. //
  673. // Query succeeded format the response data into the buffer pointed
  674. // at by transaction->OutData
  675. //
  676. namedPipeInfo = (PNAMED_PIPE_INFORMATION_1)transaction->OutData;
  677. if ((pipeLocalInformation.OutboundQuota & 0xffff0000) != 0) {
  678. SmbPutAlignedUshort(
  679. &namedPipeInfo->OutputBufferSize,
  680. (USHORT)0xFFFF
  681. );
  682. } else {
  683. SmbPutAlignedUshort(
  684. &namedPipeInfo->OutputBufferSize,
  685. (USHORT)pipeLocalInformation.OutboundQuota
  686. );
  687. }
  688. if ((pipeLocalInformation.InboundQuota & 0xffff0000) != 0) {
  689. SmbPutAlignedUshort(
  690. &namedPipeInfo->InputBufferSize,
  691. (USHORT)0xFFFF
  692. );
  693. } else {
  694. SmbPutAlignedUshort(
  695. &namedPipeInfo->InputBufferSize,
  696. (USHORT)pipeLocalInformation.InboundQuota
  697. );
  698. }
  699. if ((pipeLocalInformation.MaximumInstances & 0xffffff00) != 0) {
  700. namedPipeInfo->MaximumInstances = (UCHAR)0xFF;
  701. } else {
  702. namedPipeInfo->MaximumInstances =
  703. (UCHAR)pipeLocalInformation.MaximumInstances;
  704. }
  705. if ((pipeLocalInformation.CurrentInstances & 0xffffff00) != 0) {
  706. namedPipeInfo->CurrentInstances = (UCHAR)0xFF;
  707. } else {
  708. namedPipeInfo->CurrentInstances =
  709. (UCHAR)pipeLocalInformation.CurrentInstances;
  710. }
  711. if ( returnPipeName ) {
  712. //
  713. // Copy full pipe path name to the output buffer, appending a NUL.
  714. //
  715. // *** Note that Unicode pipe names must be aligned in the SMB.
  716. //
  717. namedPipeInfo->PipeNameLength = (UCHAR)smbPathLength;
  718. if ( isUnicode ) {
  719. PVOID buffer = ALIGN_SMB_WSTR( namedPipeInfo->PipeName );
  720. RtlCopyMemory( buffer, pipeName->Buffer, smbPathLength );
  721. } else {
  722. UNICODE_STRING source;
  723. OEM_STRING destination;
  724. source.Buffer = pipeName->Buffer;
  725. source.Length = pipeName->Length;
  726. source.MaximumLength = source.Length;
  727. destination.Buffer = (PCHAR) namedPipeInfo->PipeName;
  728. destination.MaximumLength = (USHORT)smbPathLength;
  729. RtlUnicodeStringToOemString(
  730. &destination,
  731. &source,
  732. FALSE
  733. );
  734. }
  735. transaction->DataCount = actualDataSize;
  736. } else {
  737. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  738. transaction->DataCount =
  739. FIELD_OFFSET( NAMED_PIPE_INFORMATION_1, PipeName );
  740. }
  741. //
  742. // Set up to send success response
  743. //
  744. transaction->SetupCount = 0;
  745. transaction->ParameterCount = 0;
  746. IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
  747. if ( returnPipeName) {
  748. return SmbTransStatusSuccess;
  749. } else {
  750. return SmbTransStatusErrorWithData;
  751. }
  752. } // SrvQueryInformationNamedPipe
  753. SMB_TRANS_STATUS
  754. SrvSetStateNamedPipe (
  755. IN OUT PWORK_CONTEXT WorkContext
  756. )
  757. /*++
  758. Routine Description:
  759. This function processes a set named pipe handle state transaction
  760. SMB. The call is issued synchronously.
  761. Arguments:
  762. WorkContext - A pointer to a WORK_CONTEXT block.
  763. Return Value:
  764. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  765. smbtypes.h for a more complete description.
  766. --*/
  767. {
  768. PREQ_TRANSACTION request;
  769. PTRANSACTION transaction;
  770. HANDLE pipeHandle;
  771. IO_STATUS_BLOCK ioStatusBlock;
  772. USHORT pipeHandleState;
  773. FILE_PIPE_INFORMATION pipeInformation;
  774. NTSTATUS status;
  775. USHORT fid;
  776. PRFCB rfcb;
  777. PAGED_CODE( );
  778. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  779. transaction = WorkContext->Parameters.Transaction;
  780. //
  781. // Get the FID from the second setup word and use it to generate a
  782. // pointer to the RFCB.
  783. //
  784. // SrvVerifyFid will fill in WorkContext->Rfcb.
  785. //
  786. fid = SmbGetUshort( &transaction->InSetup[1] );
  787. rfcb = SrvVerifyFid(
  788. WorkContext,
  789. fid,
  790. FALSE,
  791. NULL, // don't serialize with raw write
  792. &status
  793. );
  794. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  795. //
  796. // Invalid file ID. Reject the request.
  797. //
  798. IF_DEBUG(SMB_ERRORS) {
  799. SrvPrint1( "SrvSetStateNamedPipe: Invalid FID: 0x%lx\n", fid );
  800. }
  801. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  802. IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
  803. return SmbTransStatusErrorWithoutData;
  804. }
  805. pipeHandle = rfcb->Lfcb->FileHandle;
  806. //
  807. // The SMB contains 2 parameter bytes. Translate these to
  808. // NT format, then attempt to set the named pipe handle state.
  809. //
  810. pipeHandleState = SmbGetUshort(
  811. (PSMB_USHORT)
  812. WorkContext->Parameters.Transaction->InParameters
  813. );
  814. pipeInformation.CompletionMode =
  815. ((ULONG)pipeHandleState >> PIPE_COMPLETION_MODE_BITS) & 1;
  816. pipeInformation.ReadMode =
  817. ((ULONG)pipeHandleState >> PIPE_READ_MODE_BITS) & 1;
  818. status = NtSetInformationFile (
  819. pipeHandle,
  820. &ioStatusBlock,
  821. (PVOID)&pipeInformation,
  822. sizeof(pipeInformation),
  823. FilePipeInformation
  824. );
  825. if (NT_SUCCESS(status) ) {
  826. status = ioStatusBlock.Status;
  827. }
  828. if (!NT_SUCCESS(status)) {
  829. INTERNAL_ERROR(
  830. ERROR_LEVEL_UNEXPECTED,
  831. "SrvSetStateNamedPipe: NetSetInformationFile (pipe information) "
  832. "returned %X",
  833. status,
  834. NULL
  835. );
  836. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  837. SrvSetSmbError( WorkContext, status );
  838. IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
  839. return SmbTransStatusErrorWithoutData;
  840. }
  841. //
  842. // Success. Update our internal pipe handle state.
  843. //
  844. rfcb->BlockingModePipe =
  845. (BOOLEAN)(pipeInformation.CompletionMode ==
  846. FILE_PIPE_QUEUE_OPERATION);
  847. rfcb->ByteModePipe =
  848. (BOOLEAN)(pipeInformation.ReadMode == FILE_PIPE_BYTE_STREAM_MODE);
  849. //
  850. // Now set up for the success response.
  851. //
  852. transaction->SetupCount = 0;
  853. transaction->ParameterCount = 0;
  854. transaction->DataCount = 0;
  855. IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
  856. return SmbTransStatusSuccess;
  857. } // SrvSetStateNamedPipe
  858. SMB_TRANS_STATUS
  859. SrvPeekNamedPipe (
  860. IN OUT PWORK_CONTEXT WorkContext
  861. )
  862. /*++
  863. Routine Description:
  864. This function handles a peek named pipe transaction SMB. The
  865. call is issued asynchrously and is completed by RestartPeekNamedPipe().
  866. Arguments:
  867. WorkContext - A pointer to a WORK_CONTEXT block.
  868. Return Value:
  869. status - The result of the operation.
  870. --*/
  871. {
  872. PTRANSACTION transaction;
  873. USHORT fid;
  874. PRFCB rfcb;
  875. PLFCB lfcb;
  876. NTSTATUS status;
  877. PAGED_CODE( );
  878. transaction = WorkContext->Parameters.Transaction;
  879. //
  880. // Get the FID from the second setup word and use it to generate a
  881. // pointer to the RFCB.
  882. //
  883. // SrvVerifyFid will fill in WorkContext->Rfcb.
  884. //
  885. fid = SmbGetUshort( &transaction->InSetup[1] );
  886. rfcb = SrvVerifyFid(
  887. WorkContext,
  888. fid,
  889. FALSE,
  890. SrvRestartExecuteTransaction, // serialize with raw write
  891. &status
  892. );
  893. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  894. if ( !NT_SUCCESS( status ) ) {
  895. //
  896. // Invalid file ID. Reject the request.
  897. //
  898. IF_DEBUG(SMB_ERRORS) {
  899. SrvPrint1( "SrvPeekNamedPipe: Invalid FID: 0x%lx\n", fid );
  900. }
  901. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  902. IF_DEBUG(TRACE2) SrvPrint0( "SrvPeekNamedPipe complete\n" );
  903. return SmbTransStatusErrorWithoutData;
  904. }
  905. //
  906. // The work item has been queued because a raw write is in
  907. // progress.
  908. //
  909. return SmbTransStatusInProgress;
  910. }
  911. //
  912. // Set the Restart Routine addresses in the work context block.
  913. //
  914. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  915. WorkContext->FspRestartRoutine = RestartPeekNamedPipe;
  916. //
  917. // Issue the request to NPFS. We expect both parameters and
  918. // data to be returned. The buffer which we offer is contiguous
  919. // and large enough to contain both.
  920. //
  921. transaction = WorkContext->Parameters.Transaction;
  922. lfcb = rfcb->Lfcb;
  923. SrvBuildIoControlRequest(
  924. WorkContext->Irp,
  925. lfcb->FileObject,
  926. WorkContext,
  927. IRP_MJ_FILE_SYSTEM_CONTROL,
  928. FSCTL_PIPE_PEEK,
  929. transaction->OutParameters,
  930. 0,
  931. NULL,
  932. transaction->MaxParameterCount + transaction->MaxDataCount,
  933. NULL,
  934. NULL
  935. );
  936. //
  937. // Pass the request to NPFS.
  938. //
  939. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  940. //
  941. // The peek was successfully started. Return the InProgress
  942. // status to the caller, indicating that the caller should do
  943. // nothing further with the SMB/WorkContext at the present time.
  944. //
  945. IF_DEBUG(TRACE2) SrvPrint0( "SrvPeekNamedPipe complete\n" );
  946. return SmbTransStatusInProgress;
  947. } // SrvPeekNamedPipe
  948. SMB_TRANS_STATUS
  949. SrvTransactNamedPipe (
  950. IN OUT PWORK_CONTEXT WorkContext
  951. )
  952. /*++
  953. Routine Description:
  954. This function handles the transact named pipe transaction SMB.
  955. The call to NPFS is issued asynchronously and is completed by
  956. RestartTransactNamedPipe()
  957. Arguments:
  958. WorkContext - A pointer to a WORK_CONTEXT block.
  959. Return Value:
  960. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  961. smbtypes.h for a more complete description.
  962. --*/
  963. {
  964. PTRANSACTION transaction;
  965. USHORT fid;
  966. PRFCB rfcb;
  967. NTSTATUS status;
  968. PIO_STACK_LOCATION irpSp;
  969. PIRP irp = WorkContext->Irp;
  970. PAGED_CODE( );
  971. transaction = WorkContext->Parameters.Transaction;
  972. //
  973. // Get the FID from the second setup word and use it to generate a
  974. // pointer to the RFCB.
  975. //
  976. // SrvVerifyFid will fill in WorkContext->Rfcb.
  977. //
  978. fid = SmbGetUshort( &transaction->InSetup[1] );
  979. rfcb = SrvVerifyFid(
  980. WorkContext,
  981. fid,
  982. FALSE,
  983. SrvRestartExecuteTransaction, // serialize with raw write
  984. &status
  985. );
  986. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  987. if ( !NT_SUCCESS( status ) ) {
  988. //
  989. // Invalid file ID. Reject the request.
  990. //
  991. IF_DEBUG(SMB_ERRORS) {
  992. SrvPrint1( "SrvTransactStateNamedPipe: Invalid FID: 0x%lx\n",
  993. fid );
  994. }
  995. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  996. IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
  997. return SmbTransStatusErrorWithoutData;
  998. }
  999. //
  1000. // The work item has been queued because a raw write is in
  1001. // progress.
  1002. //
  1003. return SmbTransStatusInProgress;
  1004. }
  1005. //
  1006. // Set the Restart Routine addresses in the work context block.
  1007. //
  1008. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1009. WorkContext->FspRestartRoutine = RestartTransactNamedPipe;
  1010. transaction = WorkContext->Parameters.Transaction;
  1011. //
  1012. // Inline SrvBuildIoControlRequest
  1013. //
  1014. {
  1015. //
  1016. // Get a pointer to the next stack location. This one is used to
  1017. // hold the parameters for the device I/O control request.
  1018. //
  1019. irpSp = IoGetNextIrpStackLocation( irp );
  1020. //
  1021. // Set up the completion routine.
  1022. //
  1023. IoSetCompletionRoutine(
  1024. irp,
  1025. SrvFsdIoCompletionRoutine,
  1026. (PVOID)WorkContext,
  1027. TRUE,
  1028. TRUE,
  1029. TRUE
  1030. );
  1031. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  1032. irpSp->MinorFunction = 0;
  1033. irpSp->DeviceObject = rfcb->Lfcb->DeviceObject;
  1034. irpSp->FileObject = rfcb->Lfcb->FileObject;
  1035. irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
  1036. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1037. DEBUG irp->RequestorMode = KernelMode;
  1038. irp->MdlAddress = NULL;
  1039. irp->AssociatedIrp.SystemBuffer = transaction->OutData;
  1040. irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  1041. transaction->InData;
  1042. //
  1043. // Copy the caller's parameters to the service-specific portion of the
  1044. // IRP for those parameters that are the same for all three methods.
  1045. //
  1046. irpSp->Parameters.FileSystemControl.OutputBufferLength =
  1047. transaction->MaxDataCount;
  1048. irpSp->Parameters.FileSystemControl.InputBufferLength =
  1049. transaction->DataCount;
  1050. irpSp->Parameters.FileSystemControl.FsControlCode =
  1051. FSCTL_PIPE_INTERNAL_TRANSCEIVE;
  1052. }
  1053. //
  1054. // Pass the request to NPFS.
  1055. //
  1056. (VOID)IoCallDriver( irpSp->DeviceObject, irp );
  1057. //
  1058. // The tranceive was successfully started. Return the InProgress
  1059. // status to the caller, indicating that the caller should do
  1060. // nothing further with the SMB/WorkContext at the present time.
  1061. //
  1062. IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
  1063. return SmbTransStatusInProgress;
  1064. } // SrvTransactNamedPipe
  1065. BOOLEAN
  1066. SrvFastTransactNamedPipe (
  1067. IN OUT PWORK_CONTEXT WorkContext,
  1068. OUT SMB_STATUS * SmbStatus
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This function handles the special case of a single buffer transact
  1073. named pipe transaction SMB. The call to NPFS is issued asynchronously
  1074. and is completed by RestartFastTransactNamedPipe()
  1075. Arguments:
  1076. WorkContext - A pointer to a WORK_CONTEXT block.
  1077. SmbStatus - Status of the transaction.
  1078. Return Value:
  1079. TRUE, if fastpath succeeded,
  1080. FALSE, otherwise. Server must take long path.
  1081. --*/
  1082. {
  1083. USHORT fid;
  1084. PRFCB rfcb;
  1085. PSESSION session;
  1086. NTSTATUS status;
  1087. PIO_STACK_LOCATION irpSp;
  1088. PIRP irp = WorkContext->Irp;
  1089. CLONG outputBufferSize;
  1090. CLONG maxParameterCount;
  1091. CLONG maxDataCount;
  1092. PSMB_USHORT inSetup;
  1093. PSMB_USHORT outSetup;
  1094. PCHAR outParam;
  1095. PCHAR outData;
  1096. CLONG offset;
  1097. CLONG setupOffset;
  1098. PREQ_TRANSACTION request;
  1099. PRESP_TRANSACTION response;
  1100. PSMB_HEADER header;
  1101. PAGED_CODE( );
  1102. header = WorkContext->ResponseHeader;
  1103. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  1104. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  1105. //
  1106. // Get the FID from the second setup word and use it to generate a
  1107. // pointer to the RFCB.
  1108. //
  1109. // SrvVerifyFid will fill in WorkContext->Rfcb.
  1110. //
  1111. setupOffset = (CLONG)((CLONG_PTR)(request->Buffer) - (CLONG_PTR)header);
  1112. inSetup = (PSMB_USHORT)( (PCHAR)header + setupOffset );
  1113. fid = SmbGetUshort( &inSetup[1] );
  1114. rfcb = SrvVerifyFid(
  1115. WorkContext,
  1116. fid,
  1117. FALSE,
  1118. SrvRestartSmbReceived, // serialize with raw write
  1119. &status
  1120. );
  1121. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1122. if ( !NT_SUCCESS( status ) ) {
  1123. //
  1124. // Invalid file ID. Reject the request.
  1125. //
  1126. IF_DEBUG(SMB_ERRORS) {
  1127. SrvPrint1( "SrvTransactStateNamedPipe: Invalid FID: 0x%lx\n",
  1128. fid );
  1129. }
  1130. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  1131. IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
  1132. *SmbStatus = SmbStatusSendResponse;
  1133. return TRUE;
  1134. }
  1135. //
  1136. // The work item has been queued because a raw write is in
  1137. // progress.
  1138. //
  1139. *SmbStatus = SmbStatusInProgress;
  1140. return TRUE;
  1141. }
  1142. //
  1143. // See and see if all the data will fit into the response buffer.
  1144. // Reject the long path if not the case.
  1145. // The "+1" on the MaxSetupCount calculation below accounts for the
  1146. // USHORT byte count in the buffer.
  1147. //
  1148. maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
  1149. maxDataCount = SmbGetUshort( &request->MaxDataCount );
  1150. session = rfcb->Lfcb->Session;
  1151. outputBufferSize = ((maxParameterCount * sizeof(CHAR) + 3) & ~3) +
  1152. ((maxDataCount * sizeof(CHAR) + 3) & ~3) +
  1153. (((request->MaxSetupCount + 1) * sizeof(USHORT) + 3) & ~3);
  1154. if ( sizeof(SMB_HEADER) +
  1155. sizeof (RESP_TRANSACTION) +
  1156. outputBufferSize
  1157. > (ULONG)session->MaxBufferSize) {
  1158. //
  1159. // This won't fit. Use the long path.
  1160. //
  1161. return(FALSE);
  1162. }
  1163. //
  1164. // If this operation may block, and we are running short of
  1165. // free work items, fail this SMB with an out of resources error.
  1166. //
  1167. if ( SrvReceiveBufferShortage( ) ) {
  1168. SrvStatistics.BlockingSmbsRejected++;
  1169. SrvSetSmbError(
  1170. WorkContext,
  1171. STATUS_INSUFF_SERVER_RESOURCES
  1172. );
  1173. *SmbStatus = SmbStatusSendResponse;
  1174. return TRUE;
  1175. } else {
  1176. //
  1177. // SrvBlockingOpsInProgress has already been incremented.
  1178. // Flag this work item as a blocking operation.
  1179. //
  1180. WorkContext->BlockingOperation = TRUE;
  1181. }
  1182. //
  1183. // Set the Restart Routine addresses in the work context block.
  1184. //
  1185. DEBUG WorkContext->FsdRestartRoutine = NULL;
  1186. //
  1187. // Setup pointers and locals.
  1188. //
  1189. outSetup = (PSMB_USHORT)response->Buffer;
  1190. //
  1191. // The "+1" on the end of the following calculation is to account
  1192. // for the USHORT byte count, which could overwrite data in certain
  1193. // cases should the MaxSetupCount be 0.
  1194. //
  1195. outParam = (PCHAR)(outSetup + (request->MaxSetupCount + 1));
  1196. offset = (CLONG)((outParam - (PCHAR)header + 3) & ~3);
  1197. outParam = (PCHAR)header + offset;
  1198. outData = outParam + maxParameterCount;
  1199. offset = (CLONG)((outData - (PCHAR)header + 3) & ~3);
  1200. outData = (PCHAR)header + offset;
  1201. //
  1202. // Fill in the work context parameters.
  1203. //
  1204. WorkContext->Parameters.FastTransactNamedPipe.OutSetup = outSetup;
  1205. WorkContext->Parameters.FastTransactNamedPipe.OutParam = outParam;
  1206. WorkContext->Parameters.FastTransactNamedPipe.OutData = outData;
  1207. //
  1208. // Inline SrvBuildIoControlRequest
  1209. //
  1210. {
  1211. //
  1212. // Get a pointer to the next stack location. This one is used to
  1213. // hold the parameters for the device I/O control request.
  1214. //
  1215. irpSp = IoGetNextIrpStackLocation( irp );
  1216. //
  1217. // Set up the completion routine.
  1218. //
  1219. IoSetCompletionRoutine(
  1220. irp,
  1221. RestartFastTransactNamedPipe,
  1222. (PVOID)WorkContext,
  1223. TRUE,
  1224. TRUE,
  1225. TRUE
  1226. );
  1227. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  1228. irpSp->MinorFunction = 0;
  1229. irpSp->DeviceObject = rfcb->Lfcb->DeviceObject;
  1230. irpSp->FileObject = rfcb->Lfcb->FileObject;
  1231. irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
  1232. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1233. DEBUG irp->RequestorMode = KernelMode;
  1234. irp->MdlAddress = NULL;
  1235. irp->AssociatedIrp.SystemBuffer = outData;
  1236. irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  1237. (PCHAR)header + SmbGetUshort( &request->DataOffset );
  1238. //
  1239. // Copy the caller's parameters to the service-specific portion of the
  1240. // IRP for those parameters that are the same for all three methods.
  1241. //
  1242. irpSp->Parameters.FileSystemControl.OutputBufferLength = maxDataCount;
  1243. irpSp->Parameters.FileSystemControl.InputBufferLength =
  1244. SmbGetUshort( &request->DataCount );
  1245. irpSp->Parameters.FileSystemControl.FsControlCode =
  1246. FSCTL_PIPE_INTERNAL_TRANSCEIVE;
  1247. }
  1248. //
  1249. // Pass the request to NPFS.
  1250. //
  1251. (VOID)IoCallDriver( irpSp->DeviceObject, irp );
  1252. //
  1253. // The tranceive was successfully started. Return the InProgress
  1254. // status to the caller, indicating that the caller should do
  1255. // nothing further with the SMB/WorkContext at the present time.
  1256. //
  1257. IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
  1258. *SmbStatus = SmbStatusInProgress;
  1259. return TRUE;
  1260. } // SrvFastTransactNamedPipe
  1261. SMB_TRANS_STATUS
  1262. SrvRawWriteNamedPipe (
  1263. IN OUT PWORK_CONTEXT WorkContext
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This function handles the raw write named pipe transaction SMB.
  1268. The call to NPFS is issued asynchronously and is completed by
  1269. RestartRawWriteNamedPipe().
  1270. Arguments:
  1271. WorkContext - A pointer to a WORK_CONTEXT block.
  1272. Return Value:
  1273. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  1274. smbtypes.h for a more complete description.
  1275. --*/
  1276. {
  1277. PTRANSACTION transaction;
  1278. USHORT fid;
  1279. PRFCB rfcb;
  1280. NTSTATUS status;
  1281. PAGED_CODE( );
  1282. transaction = WorkContext->Parameters.Transaction;
  1283. //
  1284. // Get the FID from the second setup word and use it to generate a
  1285. // pointer to the RFCB.
  1286. //
  1287. // SrvVerifyFid will fill in WorkContext->Rfcb.
  1288. //
  1289. fid = SmbGetUshort( &transaction->InSetup[1] );
  1290. rfcb = SrvVerifyFid(
  1291. WorkContext,
  1292. fid,
  1293. FALSE,
  1294. SrvRestartExecuteTransaction, // serialize with raw write
  1295. &status
  1296. );
  1297. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1298. if ( !NT_SUCCESS( status ) ) {
  1299. //
  1300. // Invalid file ID. Reject the request.
  1301. //
  1302. IF_DEBUG(SMB_ERRORS) {
  1303. SrvPrint1( "SrvRawWriteStateNamedPipe: Invalid FID: 0x%lx\n",
  1304. fid );
  1305. }
  1306. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  1307. IF_DEBUG(TRACE2) SrvPrint0( "SrvRawWriteNamedPipe complete\n" );
  1308. return SmbTransStatusErrorWithoutData;
  1309. }
  1310. //
  1311. // The work item has been queued because a raw write is in
  1312. // progress.
  1313. //
  1314. return SmbTransStatusInProgress;
  1315. }
  1316. //
  1317. // We only allow the special 0 bytes message mode write. Otherwise
  1318. // reject the request.
  1319. //
  1320. if ( transaction->DataCount != 2 ||
  1321. transaction->InData[0] != 0 ||
  1322. transaction->InData[1] != 0 ||
  1323. rfcb->ByteModePipe ) {
  1324. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  1325. return SmbTransStatusErrorWithoutData;
  1326. }
  1327. //
  1328. // Set the Restart Routine addresses in the work context block.
  1329. //
  1330. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1331. WorkContext->FspRestartRoutine = RestartRawWriteNamedPipe;
  1332. SrvBuildIoControlRequest(
  1333. WorkContext->Irp,
  1334. rfcb->Lfcb->FileObject,
  1335. WorkContext,
  1336. IRP_MJ_FILE_SYSTEM_CONTROL,
  1337. FSCTL_PIPE_INTERNAL_WRITE,
  1338. transaction->InData,
  1339. 0,
  1340. NULL,
  1341. 0,
  1342. NULL,
  1343. NULL
  1344. );
  1345. //
  1346. // Pass the request to NPFS.
  1347. //
  1348. IoCallDriver( rfcb->Lfcb->DeviceObject, WorkContext->Irp );
  1349. //
  1350. // The write was successfully started. Return the InProgress
  1351. // status to the caller, indicating that the caller should do
  1352. // nothing further with the SMB/WorkContext at the present time.
  1353. //
  1354. IF_DEBUG(TRACE2) SrvPrint0( "SrvRawWriteNamedPipe complete\n" );
  1355. return SmbTransStatusInProgress;
  1356. } // SrvRawWriteNamedPipe
  1357. VOID SRVFASTCALL
  1358. RestartCallNamedPipe (
  1359. IN OUT PWORK_CONTEXT WorkContext
  1360. )
  1361. /*++
  1362. Routine Description:
  1363. This is the completion routine for SrvCallNamedPipe
  1364. Arguments:
  1365. WorkContext - A pointer to a WORK_CONTEXT block.
  1366. Return Value:
  1367. None.
  1368. --*/
  1369. {
  1370. NTSTATUS status;
  1371. PTRANSACTION transaction;
  1372. PAGED_CODE( );
  1373. //
  1374. // If the transceive request failed, set an error status in the response
  1375. // header.
  1376. //
  1377. status = WorkContext->Irp->IoStatus.Status;
  1378. transaction = WorkContext->Parameters.Transaction;
  1379. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1380. //
  1381. // Down level clients, expect us to return STATUS_SUCCESS.
  1382. //
  1383. if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  1384. status = STATUS_SUCCESS;
  1385. } else {
  1386. //
  1387. // The buffer we supplied is not big enough. Set the
  1388. // error fields in the SMB, but continue so that we send
  1389. // all the information.
  1390. //
  1391. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  1392. }
  1393. } else if ( !NT_SUCCESS(status) ) {
  1394. IF_DEBUG(ERRORS) {
  1395. SrvPrint1( "RestartCallNamedPipe: Pipe transceive failed: %X\n",
  1396. status );
  1397. }
  1398. SrvSetSmbError( WorkContext, status );
  1399. } else {
  1400. //
  1401. // Success. Prepare to generate and send the response.
  1402. //
  1403. transaction->SetupCount = 0;
  1404. transaction->ParameterCount = 0;
  1405. transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
  1406. }
  1407. //
  1408. // Close the open pipe handle.
  1409. //
  1410. SRVDBG_RELEASE_HANDLE( transaction->FileHandle, "FIL", 19, transaction );
  1411. SrvNtClose( transaction->FileHandle, TRUE );
  1412. ObDereferenceObject( transaction->FileObject );
  1413. //
  1414. // Respond to the client
  1415. //
  1416. if ( NT_SUCCESS(status) ) {
  1417. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  1418. } else if ( status == STATUS_BUFFER_OVERFLOW ) {
  1419. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
  1420. } else {
  1421. IF_DEBUG(ERRORS) SrvPrint1( "Pipe call failed: %X\n", status );
  1422. SrvSetSmbError( WorkContext, status );
  1423. SrvCompleteExecuteTransaction(
  1424. WorkContext,
  1425. SmbTransStatusErrorWithoutData
  1426. );
  1427. }
  1428. IF_DEBUG(TRACE2) SrvPrint0( "RestartCallNamedPipe complete\n" );
  1429. return;
  1430. } // RestartCallNamedPipe
  1431. VOID SRVFASTCALL
  1432. RestartWaitNamedPipe (
  1433. IN OUT PWORK_CONTEXT WorkContext
  1434. )
  1435. /*++
  1436. Routine Description:
  1437. This is the completion routine for SrvWaitNamedPipe
  1438. Arguments:
  1439. WorkContext - A pointer to a WORK_CONTEXT block.
  1440. Return Value:
  1441. None.
  1442. --*/
  1443. {
  1444. PTRANSACTION transaction;
  1445. NTSTATUS status;
  1446. PAGED_CODE( );
  1447. //
  1448. // Deallocate the wait buffer.
  1449. //
  1450. DEALLOCATE_NONPAGED_POOL( WorkContext->Irp->AssociatedIrp.SystemBuffer );
  1451. //
  1452. // If the wait request failed, set an error status in the response
  1453. // header.
  1454. //
  1455. status = WorkContext->Irp->IoStatus.Status;
  1456. if ( !NT_SUCCESS(status) ) {
  1457. IF_DEBUG(ERRORS) SrvPrint1( "Pipe wait failed: %X\n", status );
  1458. SrvSetSmbError( WorkContext, status );
  1459. SrvCompleteExecuteTransaction(
  1460. WorkContext,
  1461. SmbTransStatusErrorWithoutData
  1462. );
  1463. IF_DEBUG(TRACE2) SrvPrint0( "RestartWaitNamedPipe complete\n" );
  1464. return;
  1465. }
  1466. //
  1467. // Success. Prepare to generate and send the response.
  1468. //
  1469. transaction = WorkContext->Parameters.Transaction;
  1470. transaction->SetupCount = 0;
  1471. transaction->ParameterCount = 0;
  1472. transaction->DataCount = 0;
  1473. //
  1474. // Generate and send the response.
  1475. //
  1476. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  1477. IF_DEBUG(TRACE2) SrvPrint0( "RestartWaitNamedPipe complete\n" );
  1478. return;
  1479. } // RestartWaitNamedPipe
  1480. VOID SRVFASTCALL
  1481. RestartPeekNamedPipe (
  1482. IN OUT PWORK_CONTEXT WorkContext
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. This is the completion routine for PeekNamedPipe
  1487. Arguments:
  1488. WorkContext - A pointer to a WORK_CONTEXT block.
  1489. Return Value:
  1490. None.
  1491. --*/
  1492. {
  1493. NTSTATUS status;
  1494. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  1495. PRESP_PEEK_NMPIPE respPeekNmPipe;
  1496. USHORT readDataAvailable, messageLength, namedPipeState;
  1497. PTRANSACTION transaction;
  1498. PAGED_CODE( );
  1499. //
  1500. // If the peek request failed, set an error status in the response
  1501. // header.
  1502. //
  1503. status = WorkContext->Irp->IoStatus.Status;
  1504. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1505. //
  1506. // Down level clients, expect us to return STATUS_SUCCESS.
  1507. //
  1508. if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  1509. status = STATUS_SUCCESS;
  1510. } else {
  1511. //
  1512. // The buffer we supplied is not big enough. Set the
  1513. // error fields in the SMB, but continue so that we send
  1514. // all the information.
  1515. //
  1516. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  1517. }
  1518. } else if ( !NT_SUCCESS(status) ) {
  1519. IF_DEBUG(ERRORS) SrvPrint1( "Pipe peek failed: %X\n", status );
  1520. SrvSetSmbError( WorkContext, status );
  1521. SrvCompleteExecuteTransaction(
  1522. WorkContext,
  1523. SmbTransStatusErrorWithoutData
  1524. );
  1525. IF_DEBUG(TRACE2) SrvPrint0( "RestartPeekNamedPipe complete\n" );
  1526. return;
  1527. }
  1528. //
  1529. // Success. Generate and send the response.
  1530. //
  1531. // The parameter bytes are currently in the format returned by NT.
  1532. // we will reformat them, and leave the extra space between the
  1533. // parameter and data bytes as extra pad.
  1534. //
  1535. //
  1536. // Since the NT and SMB formats overlap
  1537. // First read all the parameters into locals...
  1538. //
  1539. transaction = WorkContext->Parameters.Transaction;
  1540. pipePeekBuffer = (PFILE_PIPE_PEEK_BUFFER)transaction->OutParameters;
  1541. readDataAvailable = (USHORT)pipePeekBuffer->ReadDataAvailable;
  1542. messageLength = (USHORT)pipePeekBuffer->MessageLength;
  1543. namedPipeState = (USHORT)pipePeekBuffer->NamedPipeState;
  1544. //
  1545. // ... then copy them back in the new format.
  1546. //
  1547. respPeekNmPipe = (PRESP_PEEK_NMPIPE)pipePeekBuffer;
  1548. SmbPutAlignedUshort(
  1549. &respPeekNmPipe->ReadDataAvailable,
  1550. readDataAvailable
  1551. );
  1552. SmbPutAlignedUshort(
  1553. &respPeekNmPipe->MessageLength,
  1554. messageLength
  1555. );
  1556. SmbPutAlignedUshort(
  1557. &respPeekNmPipe->NamedPipeState,
  1558. namedPipeState
  1559. );
  1560. //
  1561. // Send the response. Set the output counts.
  1562. //
  1563. // NT return to us 4 ULONGS of parameter bytes, followed by data.
  1564. // We return to the client 6 parameter bytes.
  1565. //
  1566. transaction->SetupCount = 0;
  1567. transaction->ParameterCount = 6;
  1568. transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information -
  1569. (4 * sizeof(ULONG));
  1570. if (NT_SUCCESS(status)) {
  1571. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  1572. } else {
  1573. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
  1574. }
  1575. IF_DEBUG(TRACE2) SrvPrint0( "RestartPeekNamedPipe complete\n" );
  1576. return;
  1577. } // RestartPeekNamedPipe
  1578. VOID SRVFASTCALL
  1579. RestartTransactNamedPipe (
  1580. IN OUT PWORK_CONTEXT WorkContext
  1581. )
  1582. /*++
  1583. Routine Description:
  1584. This is the completion routine for SrvTransactNamedPipe
  1585. Arguments:
  1586. WorkContext - A pointer to a WORK_CONTEXT block.
  1587. Return Value:
  1588. None.
  1589. --*/
  1590. {
  1591. NTSTATUS status;
  1592. PTRANSACTION transaction;
  1593. PAGED_CODE( );
  1594. //
  1595. // If the transceive request failed, set an error status in the response
  1596. // header.
  1597. //
  1598. status = WorkContext->Irp->IoStatus.Status;
  1599. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1600. #if 0
  1601. //
  1602. // Down level clients, expect us to return STATUS_SUCCESS.
  1603. //
  1604. if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  1605. status = STATUS_SUCCESS;
  1606. } else {
  1607. //
  1608. // The buffer we supplied is not big enough. Set the
  1609. // error fields in the SMB, but continue so that we send
  1610. // all the information.
  1611. //
  1612. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  1613. }
  1614. #else
  1615. //
  1616. // os/2 returns ERROR_MORE_DATA in this case, why we convert
  1617. // this to NO_ERROR is a mystery.
  1618. //
  1619. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  1620. #endif
  1621. } else if ( !NT_SUCCESS(status) ) {
  1622. IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
  1623. SrvSetSmbError(WorkContext, status);
  1624. SrvCompleteExecuteTransaction(
  1625. WorkContext,
  1626. SmbTransStatusErrorWithoutData
  1627. );
  1628. IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
  1629. return;
  1630. }
  1631. //
  1632. // Success. Generate and send the response.
  1633. //
  1634. transaction = WorkContext->Parameters.Transaction;
  1635. transaction->SetupCount = 0;
  1636. transaction->ParameterCount = 0;
  1637. transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
  1638. if ( NT_SUCCESS(status) ) {
  1639. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  1640. } else {
  1641. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
  1642. }
  1643. IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
  1644. return;
  1645. } // RestartTransactNamedpipe
  1646. NTSTATUS
  1647. RestartFastTransactNamedPipe (
  1648. IN PDEVICE_OBJECT DeviceObject,
  1649. IN PIRP Irp,
  1650. IN OUT PWORK_CONTEXT WorkContext
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. This is the completion routine for SrvFastTransactNamedPipe
  1655. Arguments:
  1656. DeviceObject - Pointer to target device object for the request.
  1657. Irp - Pointer to I/O request packet
  1658. WorkContext - A pointer to a WORK_CONTEXT block.
  1659. Return Value:
  1660. STATUS_MORE_PROCESSING_REQUIRED.
  1661. --*/
  1662. {
  1663. NTSTATUS status;
  1664. PSMB_HEADER header;
  1665. PRESP_TRANSACTION response;
  1666. PSMB_USHORT byteCountPtr;
  1667. PCHAR paramPtr;
  1668. CLONG paramOffset;
  1669. PCHAR dataPtr;
  1670. CLONG dataOffset;
  1671. CLONG dataLength;
  1672. CLONG sendLength;
  1673. UNLOCKABLE_CODE( 8FIL );
  1674. //
  1675. // Reset the IRP cancelled bit.
  1676. //
  1677. Irp->Cancel = FALSE;
  1678. //
  1679. // If the transceive request failed, set an error status in the response
  1680. // header.
  1681. //
  1682. status = WorkContext->Irp->IoStatus.Status;
  1683. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1684. //
  1685. // os/2 returns ERROR_MORE_DATA in this case, why we convert
  1686. // this to NO_ERROR is a mystery.
  1687. //
  1688. SrvSetBufferOverflowError( WorkContext );
  1689. } else if ( !NT_SUCCESS(status) ) {
  1690. IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
  1691. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  1692. WorkContext->FspRestartRoutine = RestartFastTransactNamedPipe2;
  1693. QUEUE_WORK_TO_FSP( WorkContext );
  1694. return STATUS_MORE_PROCESSING_REQUIRED;
  1695. }
  1696. RestartFastTransactNamedPipe2( WorkContext );
  1697. goto error_no_data;
  1698. }
  1699. //
  1700. // Success. Generate and send the response.
  1701. //
  1702. dataLength = (CLONG)WorkContext->Irp->IoStatus.Information;
  1703. header = WorkContext->ResponseHeader;
  1704. //
  1705. // Save a pointer to the byte count field.
  1706. //
  1707. // If the output data and parameters are not already in the SMB
  1708. // buffer we must calculate how much of the parameters and data can
  1709. // be sent in this response. The maximum amount we can send is
  1710. // minimum of the size of our buffer and the size of the client's
  1711. // buffer.
  1712. //
  1713. // The parameter and data byte blocks are aligned on longword
  1714. // boundaries in the message.
  1715. //
  1716. byteCountPtr = WorkContext->Parameters.FastTransactNamedPipe.OutSetup;
  1717. //
  1718. // The data and paramter are already in the SMB buffer. The entire
  1719. // response will fit in one response buffer and there is no copying
  1720. // to do.
  1721. //
  1722. paramPtr = WorkContext->Parameters.FastTransactNamedPipe.OutParam;
  1723. paramOffset = (CLONG)(paramPtr - (PCHAR)header);
  1724. dataPtr = WorkContext->Parameters.FastTransactNamedPipe.OutData;
  1725. dataOffset = (CLONG)(dataPtr - (PCHAR)header);
  1726. //
  1727. // The client wants a response. Build the first (and possibly only)
  1728. // response. The last received SMB of the transaction request was
  1729. // retained for this purpose.
  1730. //
  1731. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  1732. //
  1733. // Build the parameters portion of the response.
  1734. //
  1735. response->WordCount = (UCHAR)10;
  1736. SmbPutUshort( &response->TotalParameterCount,
  1737. (USHORT)0
  1738. );
  1739. SmbPutUshort( &response->TotalDataCount,
  1740. (USHORT)dataLength
  1741. );
  1742. SmbPutUshort( &response->Reserved, 0 );
  1743. response->SetupCount = (UCHAR)0;
  1744. response->Reserved2 = 0;
  1745. //
  1746. // We need to be sure we're not sending uninitialized kernel memory
  1747. // back to the client with the response, so zero out the range between
  1748. // byteCountPtr and dataPtr.
  1749. //
  1750. RtlZeroMemory(byteCountPtr,(ULONG)(dataPtr - (PCHAR)byteCountPtr));
  1751. //
  1752. // Finish filling in the response parameters.
  1753. //
  1754. SmbPutUshort( &response->ParameterCount, (USHORT)0 );
  1755. SmbPutUshort( &response->ParameterOffset, (USHORT)paramOffset );
  1756. SmbPutUshort( &response->ParameterDisplacement, 0 );
  1757. SmbPutUshort( &response->DataCount, (USHORT)dataLength );
  1758. SmbPutUshort( &response->DataOffset, (USHORT)dataOffset );
  1759. SmbPutUshort( &response->DataDisplacement, 0 );
  1760. SmbPutUshort(
  1761. byteCountPtr,
  1762. (USHORT)(dataPtr - (PCHAR)(byteCountPtr + 1) + dataLength)
  1763. );
  1764. //
  1765. // Calculate the length of the response message.
  1766. //
  1767. sendLength = (CLONG)( dataPtr + dataLength -
  1768. (PCHAR)WorkContext->ResponseHeader );
  1769. WorkContext->ResponseBuffer->DataLength = sendLength;
  1770. //
  1771. // Set the bit in the SMB that indicates this is a response from the
  1772. // server.
  1773. //
  1774. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  1775. //
  1776. // Send the response.
  1777. //
  1778. SRV_START_SEND_2(
  1779. WorkContext,
  1780. SrvFsdRestartSmbAtSendCompletion,
  1781. NULL,
  1782. NULL
  1783. );
  1784. error_no_data:
  1785. //
  1786. // The response send is in progress. The caller will assume
  1787. // the we will handle send completion.
  1788. //
  1789. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  1790. // will stop working on the IRP.
  1791. //
  1792. IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
  1793. return STATUS_MORE_PROCESSING_REQUIRED;
  1794. } // RestartFastTransactNamedPipe
  1795. VOID SRVFASTCALL
  1796. RestartFastTransactNamedPipe2 (
  1797. IN OUT PWORK_CONTEXT WorkContext
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. This is the completion routine for SrvFastTransactNamedPipe
  1802. Arguments:
  1803. WorkContext - A pointer to a WORK_CONTEXT block.
  1804. Return Value:
  1805. None.
  1806. --*/
  1807. {
  1808. PAGED_CODE( );
  1809. //
  1810. // The transceive request failed. Set an error status in the response
  1811. // header.
  1812. //
  1813. SrvSetSmbError( WorkContext, WorkContext->Irp->IoStatus.Status );
  1814. //
  1815. // An error occurred, so no transaction-specific response data
  1816. // will be returned.
  1817. //
  1818. // Calculate the length of the response message.
  1819. //
  1820. WorkContext->ResponseBuffer->DataLength =
  1821. (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  1822. (PCHAR)WorkContext->ResponseHeader );
  1823. //
  1824. // Send the response.
  1825. //
  1826. SRV_START_SEND_2(
  1827. WorkContext,
  1828. SrvFsdRestartSmbAtSendCompletion,
  1829. NULL,
  1830. NULL
  1831. );
  1832. return;
  1833. } // RestartFastTransactNamedPipe2
  1834. VOID SRVFASTCALL
  1835. RestartRawWriteNamedPipe (
  1836. IN OUT PWORK_CONTEXT WorkContext
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. This is the completion routine for SrvRawWriteNamedPipe
  1841. Arguments:
  1842. WorkContext - A pointer to a WORK_CONTEXT block.
  1843. Return Value:
  1844. None.
  1845. --*/
  1846. {
  1847. NTSTATUS status;
  1848. PTRANSACTION transaction;
  1849. PAGED_CODE( );
  1850. //
  1851. // If the write request failed, set an error status in the response
  1852. // header.
  1853. //
  1854. status = WorkContext->Irp->IoStatus.Status;
  1855. if ( !NT_SUCCESS(status) ) {
  1856. IF_DEBUG(ERRORS) SrvPrint1( "Pipe raw write failed: %X\n", status );
  1857. SrvSetSmbError( WorkContext, status );
  1858. SrvCompleteExecuteTransaction(
  1859. WorkContext,
  1860. SmbTransStatusErrorWithoutData
  1861. );
  1862. IF_DEBUG(TRACE2) SrvPrint0( "RestartRawWriteNamedPipe complete\n" );
  1863. return;
  1864. }
  1865. //
  1866. // Success. Generate and send the response.
  1867. //
  1868. transaction = WorkContext->Parameters.Transaction;
  1869. transaction->SetupCount = 0;
  1870. transaction->ParameterCount = 2;
  1871. transaction->DataCount = 0;
  1872. SmbPutUshort( (PSMB_USHORT)transaction->OutParameters, 2 );
  1873. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  1874. IF_DEBUG(TRACE2) SrvPrint0( "RestartRawWriteNamedPipe complete\n" );
  1875. return;
  1876. } // RestartRawWriteNamedpipe
  1877. SMB_TRANS_STATUS
  1878. SrvWriteNamedPipe (
  1879. IN OUT PWORK_CONTEXT WorkContext
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. This function handles the raw write named pipe transaction SMB.
  1884. The call to NPFS is issued asynchronously and is completed by
  1885. RestartRawWriteNamedPipe().
  1886. Arguments:
  1887. WorkContext - A pointer to a WORK_CONTEXT block.
  1888. Return Value:
  1889. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  1890. smbtypes.h for a more complete description.
  1891. --*/
  1892. {
  1893. PTRANSACTION transaction;
  1894. USHORT fid;
  1895. PRFCB rfcb;
  1896. PLFCB lfcb;
  1897. NTSTATUS status;
  1898. LARGE_INTEGER offset;
  1899. ULONG key = 0;
  1900. PCHAR writeAddress;
  1901. CLONG writeLength;
  1902. PAGED_CODE( );
  1903. transaction = WorkContext->Parameters.Transaction;
  1904. //
  1905. // Get the FID from the second setup word and use it to generate a
  1906. // pointer to the RFCB.
  1907. //
  1908. // SrvVerifyFid will fill in WorkContext->Rfcb.
  1909. //
  1910. fid = SmbGetUshort( &transaction->InSetup[1] );
  1911. IF_DEBUG(IPX_PIPES) {
  1912. KdPrint(("SrvWriteNamedPipe: fid = %x length = %d\n",
  1913. fid, transaction->DataCount));
  1914. }
  1915. rfcb = SrvVerifyFid(
  1916. WorkContext,
  1917. fid,
  1918. FALSE,
  1919. SrvRestartExecuteTransaction, // serialize with raw write
  1920. &status
  1921. );
  1922. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1923. if ( !NT_SUCCESS( status ) ) {
  1924. //
  1925. // Invalid file ID. Reject the request.
  1926. //
  1927. IF_DEBUG(SMB_ERRORS) {
  1928. SrvPrint1( "SrvWriteNamedPipe: Invalid FID: 0x%lx\n",
  1929. fid );
  1930. }
  1931. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  1932. IF_DEBUG(TRACE2) SrvPrint0( "SrvWriteNamedPipe complete\n" );
  1933. return SmbTransStatusErrorWithoutData;
  1934. }
  1935. //
  1936. // The work item has been queued because a raw write is in
  1937. // progress.
  1938. //
  1939. return SmbTransStatusInProgress;
  1940. }
  1941. lfcb = rfcb->Lfcb;
  1942. writeLength = transaction->DataCount;
  1943. writeAddress = transaction->InData;
  1944. //
  1945. // Try the fast I/O path first. If that fails, fall through to the
  1946. // normal build-an-IRP path.
  1947. //
  1948. if ( lfcb->FastIoWrite != NULL ) {
  1949. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1950. try {
  1951. if ( lfcb->FastIoWrite(
  1952. lfcb->FileObject,
  1953. &offset,
  1954. writeLength,
  1955. TRUE,
  1956. key,
  1957. writeAddress,
  1958. &WorkContext->Irp->IoStatus,
  1959. lfcb->DeviceObject
  1960. ) ) {
  1961. //
  1962. // The fast I/O path worked. Call the restart routine directly
  1963. // to do postprocessing (including sending the response).
  1964. //
  1965. RestartWriteNamedPipe( WorkContext );
  1966. IF_DEBUG(IPX_PIPES) SrvPrint0( "SrvWriteNamedPipe complete.\n" );
  1967. return SmbTransStatusInProgress;
  1968. }
  1969. }
  1970. except( EXCEPTION_EXECUTE_HANDLER ) {
  1971. // Fall through to the slow path on an exception
  1972. NTSTATUS status = GetExceptionCode();
  1973. IF_DEBUG(ERRORS) {
  1974. KdPrint(("FastIoRead threw exception %x\n", status ));
  1975. }
  1976. }
  1977. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1978. }
  1979. IF_DEBUG(IPX_PIPES) {
  1980. KdPrint(("SrvWriteNamedPipe: Using slow path.\n"));
  1981. }
  1982. //
  1983. // The turbo path failed. Build the write request, reusing the
  1984. // receive IRP.
  1985. //
  1986. // Build the PIPE_INTERNAL_WRITE IRP.
  1987. //
  1988. SrvBuildIoControlRequest(
  1989. WorkContext->Irp,
  1990. lfcb->FileObject,
  1991. WorkContext,
  1992. IRP_MJ_FILE_SYSTEM_CONTROL,
  1993. FSCTL_PIPE_INTERNAL_WRITE,
  1994. writeAddress,
  1995. writeLength,
  1996. NULL,
  1997. 0,
  1998. NULL,
  1999. NULL
  2000. );
  2001. //
  2002. // Pass the request to the file system.
  2003. //
  2004. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2005. WorkContext->FspRestartRoutine = RestartWriteNamedPipe;
  2006. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2007. //
  2008. // The write has been started. Control will return to
  2009. // RestartWriteNamedPipe when the write completes.
  2010. //
  2011. IF_DEBUG(TRACE2) SrvPrint0( "SrvWriteNamedPipe complete\n" );
  2012. return SmbTransStatusInProgress;
  2013. } // SrvWriteNamedPipe
  2014. VOID SRVFASTCALL
  2015. RestartWriteNamedPipe (
  2016. IN OUT PWORK_CONTEXT WorkContext
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. This is the completion routine for SrvRawWriteNamedPipe
  2021. Arguments:
  2022. WorkContext - A pointer to a WORK_CONTEXT block.
  2023. Return Value:
  2024. None.
  2025. --*/
  2026. {
  2027. NTSTATUS status;
  2028. PIO_STATUS_BLOCK iosb;
  2029. PTRANSACTION transaction;
  2030. PAGED_CODE( );
  2031. //
  2032. // If the write request failed, set an error status in the response
  2033. // header.
  2034. //
  2035. iosb = &WorkContext->Irp->IoStatus;
  2036. status = iosb->Status;
  2037. IF_DEBUG(IPX_PIPES) {
  2038. KdPrint(("RestartWriteNamedPipe: Status = %x\n", status));
  2039. }
  2040. if ( !NT_SUCCESS(status) ) {
  2041. IF_DEBUG(ERRORS) SrvPrint1( " pipe write failed: %X\n", status );
  2042. SrvSetSmbError( WorkContext, status );
  2043. SrvCompleteExecuteTransaction(
  2044. WorkContext,
  2045. SmbTransStatusErrorWithoutData
  2046. );
  2047. IF_DEBUG(TRACE2) SrvPrint0( "RestartWriteNamedPipe complete\n" );
  2048. return;
  2049. }
  2050. //
  2051. // Success. Generate and send the response.
  2052. //
  2053. transaction = WorkContext->Parameters.Transaction;
  2054. transaction->SetupCount = 0;
  2055. transaction->ParameterCount = 2;
  2056. transaction->DataCount = 0;
  2057. SmbPutUshort( (PSMB_USHORT)transaction->OutParameters,
  2058. (USHORT)iosb->Information
  2059. );
  2060. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  2061. IF_DEBUG(TRACE2) SrvPrint0( "RestartWriteNamedPipe complete\n" );
  2062. return;
  2063. } // RestartWriteNamedPipe
  2064. SMB_TRANS_STATUS
  2065. SrvReadNamedPipe (
  2066. IN OUT PWORK_CONTEXT WorkContext
  2067. )
  2068. /*++
  2069. Routine Description:
  2070. This function handles the raw Read named pipe transaction SMB.
  2071. The call to NPFS is issued asynchronously and is completed by
  2072. RestartRawReadNamedPipe().
  2073. Arguments:
  2074. WorkContext - A pointer to a WORK_CONTEXT block.
  2075. Return Value:
  2076. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  2077. smbtypes.h for a more complete description.
  2078. --*/
  2079. {
  2080. PTRANSACTION transaction;
  2081. USHORT fid;
  2082. PRFCB rfcb;
  2083. PLFCB lfcb;
  2084. NTSTATUS status;
  2085. LARGE_INTEGER offset;
  2086. ULONG key = 0;
  2087. PCHAR readAddress;
  2088. CLONG readLength;
  2089. PAGED_CODE( );
  2090. transaction = WorkContext->Parameters.Transaction;
  2091. //
  2092. // Get the FID from the second setup word and use it to generate a
  2093. // pointer to the RFCB.
  2094. //
  2095. // SrvVerifyFid will fill in WorkContext->Rfcb.
  2096. //
  2097. fid = SmbGetUshort( &transaction->InSetup[1] );
  2098. IF_DEBUG(IPX_PIPES) {
  2099. KdPrint(("SrvReadNamedPipe: fid = %x length = %d\n",
  2100. fid, transaction->MaxDataCount));
  2101. }
  2102. rfcb = SrvVerifyFid(
  2103. WorkContext,
  2104. fid,
  2105. FALSE,
  2106. SrvRestartExecuteTransaction, // serialize with raw Read
  2107. &status
  2108. );
  2109. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  2110. if ( !NT_SUCCESS( status ) ) {
  2111. //
  2112. // Invalid file ID. Reject the request.
  2113. //
  2114. IF_DEBUG(SMB_ERRORS) {
  2115. SrvPrint1( "SrvReadNamedPipe: Invalid FID: 0x%lx\n",
  2116. fid );
  2117. }
  2118. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  2119. IF_DEBUG(TRACE2) SrvPrint0( "SrvReadNamedPipe complete\n" );
  2120. return SmbTransStatusErrorWithoutData;
  2121. }
  2122. //
  2123. // The work item has been queued because a raw Read is in
  2124. // progress.
  2125. //
  2126. return SmbTransStatusInProgress;
  2127. }
  2128. lfcb = rfcb->Lfcb;
  2129. readLength = transaction->MaxDataCount;
  2130. readAddress = transaction->OutData;
  2131. //
  2132. // Try the fast I/O path first. If that fails, fall through to the
  2133. // normal build-an-IRP path.
  2134. //
  2135. if ( lfcb->FastIoRead != NULL ) {
  2136. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  2137. try {
  2138. if ( lfcb->FastIoRead(
  2139. lfcb->FileObject,
  2140. &offset,
  2141. readLength,
  2142. TRUE,
  2143. key,
  2144. readAddress,
  2145. &WorkContext->Irp->IoStatus,
  2146. lfcb->DeviceObject
  2147. ) ) {
  2148. //
  2149. // The fast I/O path worked. Call the restart routine directly
  2150. // to do postprocessing (including sending the response).
  2151. //
  2152. RestartReadNamedPipe( WorkContext );
  2153. IF_SMB_DEBUG(READ_WRITE2) SrvPrint0( "SrvReadNamedPipe complete.\n" );
  2154. return SmbTransStatusInProgress;
  2155. }
  2156. }
  2157. except( EXCEPTION_EXECUTE_HANDLER ) {
  2158. // Fall through to the slow path on an exception
  2159. NTSTATUS status = GetExceptionCode();
  2160. IF_DEBUG(ERRORS) {
  2161. KdPrint(("FastIoRead threw exception %x\n", status ));
  2162. }
  2163. }
  2164. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  2165. }
  2166. //
  2167. // The turbo path failed. Build the Read request, reusing the
  2168. // receive IRP.
  2169. //
  2170. // Build the PIPE_INTERNAL_READ IRP.
  2171. //
  2172. SrvBuildIoControlRequest(
  2173. WorkContext->Irp,
  2174. lfcb->FileObject,
  2175. WorkContext,
  2176. IRP_MJ_FILE_SYSTEM_CONTROL,
  2177. FSCTL_PIPE_INTERNAL_READ,
  2178. readAddress,
  2179. 0,
  2180. NULL,
  2181. readLength,
  2182. NULL,
  2183. NULL
  2184. );
  2185. //
  2186. // Pass the request to the file system.
  2187. //
  2188. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2189. WorkContext->FspRestartRoutine = RestartReadNamedPipe;
  2190. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2191. //
  2192. // The Read has been started. Control will return to
  2193. // SrvFsdRestartRead when the Read completes.
  2194. //
  2195. IF_DEBUG(TRACE2) SrvPrint0( "SrvReadNamedPipe complete\n" );
  2196. return SmbTransStatusInProgress;
  2197. } // SrvReadNamedPipe
  2198. VOID SRVFASTCALL
  2199. RestartReadNamedPipe (
  2200. IN OUT PWORK_CONTEXT WorkContext
  2201. )
  2202. /*++
  2203. Routine Description:
  2204. This is the completion routine for SrvRawReadNamedPipe
  2205. Arguments:
  2206. WorkContext - A pointer to a WORK_CONTEXT block.
  2207. Return Value:
  2208. None.
  2209. --*/
  2210. {
  2211. NTSTATUS status;
  2212. PTRANSACTION transaction;
  2213. PAGED_CODE( );
  2214. //
  2215. // If the transceive request failed, set an error status in the response
  2216. // header.
  2217. //
  2218. status = WorkContext->Irp->IoStatus.Status;
  2219. if ( status == STATUS_BUFFER_OVERFLOW ) {
  2220. SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
  2221. } else if ( !NT_SUCCESS(status) ) {
  2222. IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
  2223. SrvSetSmbError(WorkContext, status);
  2224. SrvCompleteExecuteTransaction(
  2225. WorkContext,
  2226. SmbTransStatusErrorWithoutData
  2227. );
  2228. IF_DEBUG(TRACE2) SrvPrint0( "RestartReadNamedPipe complete\n" );
  2229. return;
  2230. }
  2231. //
  2232. // Success. Generate and send the response.
  2233. //
  2234. transaction = WorkContext->Parameters.Transaction;
  2235. transaction->SetupCount = 0;
  2236. transaction->ParameterCount = 0;
  2237. transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
  2238. if ( NT_SUCCESS(status) ) {
  2239. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  2240. } else {
  2241. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
  2242. }
  2243. IF_DEBUG(TRACE2) SrvPrint0( "RestartReadNamedPipe complete\n" );
  2244. return;
  2245. } // RestartReadNamedPipe