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.

2602 lines
92 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. fsctl.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining to
  7. file system control(FSCTL) and Io Device Control (IOCTL) operations on file
  8. system objects.
  9. Author:
  10. Balan Sethu Raman [SethuR] 7-March-1995
  11. Revision History:
  12. Joe Linn [JoeLi] -- Implemented FSCTL's
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <dfsfsctl.h>
  17. #include <ntddrdr.h>
  18. #include <wincred.h>
  19. #include <secpkg.h>
  20. #include <srvfsctl.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, MRxSmbFsCtl)
  23. #pragma alloc_text(PAGE, MRxSmbNotifyChangeDirectory)
  24. #pragma alloc_text(PAGE, MRxSmbNamedPipeFsControl)
  25. #pragma alloc_text(PAGE, MRxSmbFsCtlUserTransact)
  26. #pragma alloc_text(PAGE, MRxSmbMailSlotFsControl)
  27. #pragma alloc_text(PAGE, MRxSmbFsControl)
  28. #pragma alloc_text(PAGE, MRxSmbIoCtl)
  29. #endif
  30. //
  31. // The local debug trace level
  32. //
  33. RXDT_DefineCategory(FSCTRL);
  34. #define Dbg (DEBUG_TRACE_FSCTRL)
  35. extern
  36. NTSTATUS
  37. MRxSmbNamedPipeFsControl(IN OUT PRX_CONTEXT RxContext);
  38. extern
  39. NTSTATUS
  40. MRxSmbMailSlotFsControl(IN OUT PRX_CONTEXT RxContext);
  41. extern
  42. NTSTATUS
  43. MRxSmbDfsFsControl(IN OUT PRX_CONTEXT RxContext);
  44. extern
  45. NTSTATUS
  46. MRxSmbFsControl(IN OUT PRX_CONTEXT RxContext);
  47. extern
  48. NTSTATUS
  49. MRxSmbFsCtlUserTransact(IN OUT PRX_CONTEXT RxContext);
  50. NTSTATUS
  51. MRxSmbGetPrintJobId(
  52. IN OUT PRX_CONTEXT RxContext);
  53. NTSTATUS
  54. MRxSmbCoreIoCtl(
  55. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE);
  56. NTSTATUS
  57. MRxSmbQueryTargetInfo(
  58. PRX_CONTEXT RxContext
  59. );
  60. NTSTATUS
  61. MRxSmbQueryRemoteServerName(
  62. PRX_CONTEXT RxContext
  63. );
  64. NTSTATUS
  65. MRxSmbFsCtl(
  66. IN OUT PRX_CONTEXT RxContext)
  67. /*++
  68. Routine Description:
  69. This routine performs an FSCTL operation (remote) on a file across the network
  70. Arguments:
  71. RxContext - the RDBSS context
  72. Return Value:
  73. RXSTATUS - The return status for the operation
  74. Notes:
  75. The FSCTL's handled by a mini rdr can be classified into one of two categories.
  76. In the first category are those FSCTL's whose implementation are shared between
  77. RDBSS and the mini rdr's and in the second category are those FSCTL's which
  78. are totally implemented by the mini rdr's. To this a third category can be
  79. added, i.e., those FSCTL's which should never be seen by the mini rdr's. The
  80. third category is solely intended as a debugging aid.
  81. The FSCTL's handled by a mini rdr can be classified based on functionality
  82. --*/
  83. {
  84. RxCaptureFobx;
  85. RxCaptureFcb;
  86. NTSTATUS Status = STATUS_SUCCESS;
  87. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  88. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  89. PAGED_CODE();
  90. RxDbgTrace(+1, Dbg, ("MRxSmbFsCtl...\n", 0));
  91. RxDbgTrace( 0, Dbg, ("MRxSmbFsCtl = %08lx\n", FsControlCode));
  92. if (capFobx != NULL) {
  93. PMRX_V_NET_ROOT pVNetRoot;
  94. // Avoid device opens for which the FOBX is the VNET_ROOT instance
  95. pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  96. if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
  97. PUNICODE_STRING AlreadyPrefixedName =
  98. GET_ALREADY_PREFIXED_NAME(capFobx->pSrvOpen,capFcb);
  99. ULONG FcbAlreadyPrefixedNameLength = AlreadyPrefixedName->Length;
  100. ULONG NetRootInnerNamePrefixLength = capFcb->pNetRoot->InnerNamePrefix.Length;
  101. PWCHAR pName = AlreadyPrefixedName->Buffer;
  102. // If an FSCTL is being attempted against the root of a share.
  103. // The AlreadyPrefixedName associated with the FCB is the same as
  104. // the AlreadyPrefixedName length associated with the NET_ROOT instance
  105. // or atmost one character greater than it ( appending a \) try and
  106. // reestablish the connection before attempting the FSCTL.
  107. // This solves thorny issues regarding deletion/creation of shares
  108. // on the server sides, DFS referrals etc.
  109. if ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength) ||
  110. ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength + sizeof(WCHAR)) &&
  111. (*((PCHAR)pName + FcbAlreadyPrefixedNameLength - sizeof(WCHAR)) ==
  112. L'\\'))) {
  113. if (capFobx->pSrvOpen != NULL) {
  114. Status = SmbCeReconnect(capFobx->pSrvOpen->pVNetRoot);
  115. }
  116. }
  117. }
  118. }
  119. if (Status == STATUS_SUCCESS) {
  120. switch (pLowIoContext->ParamsFor.FsCtl.MinorFunction) {
  121. case IRP_MN_USER_FS_REQUEST:
  122. case IRP_MN_TRACK_LINK :
  123. switch (FsControlCode) {
  124. case FSCTL_PIPE_ASSIGN_EVENT :
  125. case FSCTL_PIPE_DISCONNECT :
  126. case FSCTL_PIPE_LISTEN :
  127. case FSCTL_PIPE_PEEK :
  128. case FSCTL_PIPE_QUERY_EVENT :
  129. case FSCTL_PIPE_TRANSCEIVE :
  130. case FSCTL_PIPE_WAIT :
  131. case FSCTL_PIPE_IMPERSONATE :
  132. case FSCTL_PIPE_SET_CLIENT_PROCESS :
  133. case FSCTL_PIPE_QUERY_CLIENT_PROCESS :
  134. Status = MRxSmbNamedPipeFsControl(RxContext);
  135. break;
  136. case FSCTL_MAILSLOT_PEEK :
  137. Status = MRxSmbMailSlotFsControl(RxContext);
  138. break;
  139. case FSCTL_DFS_GET_REFERRALS:
  140. case FSCTL_DFS_REPORT_INCONSISTENCY:
  141. Status = MRxSmbDfsFsControl(RxContext);
  142. break;
  143. case FSCTL_LMR_TRANSACT :
  144. Status = MRxSmbFsCtlUserTransact(RxContext);
  145. break;
  146. case FSCTL_GET_PRINT_ID :
  147. Status = MRxSmbGetPrintJobId(RxContext);
  148. break;
  149. case FSCTL_LMR_QUERY_TARGET_INFO:
  150. Status = MRxSmbQueryTargetInfo(RxContext);
  151. break;
  152. case IOCTL_LMR_QUERY_REMOTE_SERVER_NAME:
  153. Status = MRxSmbQueryRemoteServerName(RxContext);
  154. break;
  155. case FSCTL_MOVE_FILE:
  156. case FSCTL_MARK_HANDLE:
  157. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  158. case FSCTL_GET_VOLUME_BITMAP:
  159. case FSCTL_GET_NTFS_FILE_RECORD:
  160. Status = STATUS_NOT_SUPPORTED;
  161. break;
  162. // lwio ioctl
  163. case FSCTL_SRV_REQUEST_RESUME_KEY:
  164. if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_FILE ||
  165. capFcb->pNetRoot == NULL ||
  166. capFcb->pNetRoot->pSrvCall == NULL ||
  167. !FlagOn(capFcb->pNetRoot->pSrvCall->Flags,
  168. SRVCALL_FLAG_LWIO_AWARE_SERVER)) {
  169. return STATUS_NOT_SUPPORTED;
  170. } else {
  171. Status = MRxSmbFsControl(RxContext);
  172. }
  173. break;
  174. case FSCTL_SET_REPARSE_POINT:
  175. {
  176. ULONG InputBufferLength = 0; // invalid value as we need an input buffer
  177. PREPARSE_DATA_BUFFER prdBuff = (&RxContext->LowIoContext)->ParamsFor.FsCtl.pInputBuffer;
  178. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  179. InputBufferLength = (&RxContext->LowIoContext)->ParamsFor.FsCtl.InputBufferLength;
  180. if ((prdBuff == NULL)||
  181. (InputBufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE)||
  182. (InputBufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE))
  183. {
  184. Status = STATUS_IO_REPARSE_DATA_INVALID;
  185. break;
  186. }
  187. //
  188. // Verify that the user buffer and the data length in its header are
  189. // internally consistent. We need to have a REPARSE_DATA_BUFFER or a
  190. // REPARSE_GUID_DATA_BUFFER.
  191. //
  192. if((InputBufferLength != (ULONG)(REPARSE_DATA_BUFFER_HEADER_SIZE + prdBuff->ReparseDataLength))
  193. &&
  194. (InputBufferLength != (ULONG)(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE + prdBuff->ReparseDataLength)))
  195. {
  196. Status = STATUS_IO_REPARSE_DATA_INVALID;
  197. break;
  198. }
  199. }
  200. case FSCTL_GET_REPARSE_POINT:
  201. // absence of break intentional
  202. case FSCTL_MARK_AS_SYSTEM_HIVE :
  203. //
  204. // On a remote boot machine, we need to no-op the MARK_AS_SYSTEM_HIVE
  205. // FSCTL. Local filesystems use this to prevent a volume from being
  206. // dismounted.
  207. //
  208. if (MRxSmbBootedRemotely) {
  209. break;
  210. }
  211. default:
  212. Status = MRxSmbFsControl(RxContext);
  213. break;
  214. }
  215. break;
  216. default :
  217. Status = STATUS_INVALID_DEVICE_REQUEST;
  218. break;
  219. }
  220. }
  221. RxDbgTrace(-1, Dbg, ("MRxSmbFsCtl -> %08lx\n", Status ));
  222. return Status;
  223. }
  224. typedef struct _SMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT_ {
  225. LONG ReferenceCount;
  226. PRX_CONTEXT pRxContext;
  227. REQ_NOTIFY_CHANGE NotifyRequest;
  228. SMB_TRANSACTION_OPTIONS Options;
  229. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  230. } SMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT, *PSMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT;
  231. NTSTATUS
  232. FsRtlValidateChangeNotifyBuffer(
  233. PVOID NotifyBuffer,
  234. ULONG NotifyBufferLength )
  235. /*++
  236. Routine Description:
  237. This routine validates a change-notification buffer.
  238. typedef struct _FILE_NOTIFY_INFORMATION {
  239. ULONG NextEntryOffset;
  240. ULONG Action;
  241. ULONG FileNameLength;
  242. WCHAR FileName[1];
  243. } FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
  244. We validate the following:
  245. * NextEntryOffset points forward, and lies within the buffer
  246. * FileNameLength does not bleed into the next entry
  247. Arguments:
  248. NotifyBuffer - The change notification buffer to be validated.
  249. NotifyBufferLength - The size in bytes of the buffer
  250. Return Value:
  251. STATUS_SUCCESS if the buffer is valid.
  252. STATUS_INVALID_NETWORK_RESPONSE otherwise.
  253. Notes:
  254. --*/
  255. {
  256. ULONG CurrentOffset = 0;
  257. ULONG NextEntryOffset = 0;
  258. NTSTATUS Status = STATUS_SUCCESS;
  259. PFILE_NOTIFY_INFORMATION pInfo = (PFILE_NOTIFY_INFORMATION) NotifyBuffer;
  260. //
  261. // Return success trivially, if the buffer length is zero.
  262. //
  263. if( NotifyBufferLength == 0 ) {
  264. return STATUS_SUCCESS;
  265. }
  266. do
  267. {
  268. //
  269. // Return failure if we cannot safely read the 'NextEntryOffset'.
  270. //
  271. if( NotifyBufferLength < CurrentOffset + sizeof(ULONG) ) {
  272. ASSERT( !"'NextEntryOffset' overruns buffer" );
  273. Status = STATUS_INVALID_NETWORK_RESPONSE;
  274. break;
  275. }
  276. NextEntryOffset = *((PULONG)pInfo);
  277. if( NextEntryOffset == 0 ) {
  278. NextEntryOffset = NotifyBufferLength - CurrentOffset;
  279. }
  280. //
  281. // Make sure filename length doesnt overrun the current entry or the buffer.
  282. //
  283. if(( CurrentOffset + FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName) > NotifyBufferLength ) ||
  284. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName) > NextEntryOffset ) ||
  285. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  286. ASSERT(!"ChangeNotify FileNameLength overruns buffer");
  287. Status = STATUS_INVALID_NETWORK_RESPONSE;
  288. break;
  289. }
  290. //
  291. // If 'NextEntryOffset' is 0, then break out
  292. //
  293. if( pInfo->NextEntryOffset == 0 ) {
  294. break;
  295. }
  296. //
  297. // Check for backward links.
  298. //
  299. if( (LONG)pInfo->NextEntryOffset < 0 ) {
  300. Status = STATUS_INVALID_NETWORK_RESPONSE;
  301. ASSERT(!"ChangeNotify NextEntryOffset < 0");
  302. break;
  303. }
  304. //
  305. // Check for link which overruns the buffer
  306. //
  307. if( CurrentOffset + pInfo->NextEntryOffset >= NotifyBufferLength ) {
  308. Status = STATUS_INVALID_NETWORK_RESPONSE;
  309. ASSERT(!"ChangeNotify NextEntryOffset > NotifyBufferLength");
  310. break;
  311. }
  312. //
  313. // Check for 4 byte alignment.
  314. //
  315. if( pInfo->NextEntryOffset & 0x3 ) {
  316. Status = STATUS_INVALID_NETWORK_RESPONSE;
  317. ASSERT(!"ChangeNotify NextEntryOffset is not DWORD aligned");
  318. break;
  319. }
  320. CurrentOffset += pInfo->NextEntryOffset;
  321. pInfo = (PFILE_NOTIFY_INFORMATION) Add2Ptr( pInfo, pInfo->NextEntryOffset );
  322. } while(1);
  323. return Status;
  324. }
  325. NTSTATUS
  326. MRxSmbNotifyChangeDirectorySynchronousCompletion(
  327. PSMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext)
  328. /*++
  329. Routine Description:
  330. This routine is invoked when a directory change notification operation is
  331. completed
  332. Arguments:
  333. RxContext - the RDBSS context
  334. Return Value:
  335. RXSTATUS - The return status for the operation
  336. Notes:
  337. This routine will always be called. This is true even if the change directory
  338. notification is cancelled. In such cases the memory allocated is freed without
  339. any interaction with the wrapper. In cases of successful directory change
  340. notification completion the appropriate completion routine is invoked and the
  341. RxContext modified to prevent any cancellation from proceeding further.
  342. --*/
  343. {
  344. NTSTATUS Status = STATUS_PENDING;
  345. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  346. PRX_CONTEXT pRxContext;
  347. PSMB_EXCHANGE pExchange = NULL;
  348. BOOLEAN FinalizeNotificationContext = FALSE;
  349. SmbCeAcquireSpinLock();
  350. FinalizeNotificationContext =
  351. (InterlockedDecrement(&pNotificationContext->ReferenceCount) == 0);
  352. if (FinalizeNotificationContext) {
  353. pRxContext = pNotificationContext->pRxContext;
  354. pMRxSmbContext = MRxSmbGetMinirdrContext(pRxContext);
  355. pExchange = pMRxSmbContext->pExchange;
  356. Status = pRxContext->StoredStatus;
  357. }
  358. SmbCeReleaseSpinLock();
  359. // Free the associated exchange.
  360. if (FinalizeNotificationContext) {
  361. if (pExchange != NULL) {
  362. SmbCeDereferenceAndDiscardExchange(pExchange);
  363. }
  364. // Free the notification context.
  365. RxFreePool(pNotificationContext);
  366. ASSERT(Status != STATUS_PENDING);
  367. }
  368. return Status;
  369. }
  370. VOID
  371. MRxSmbNotifyChangeDirectoryCompletion(
  372. PSMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext)
  373. /*++
  374. Routine Description:
  375. This routine is invoked when a directory change notification operation is
  376. completed
  377. Arguments:
  378. RxContext - the RDBSS context
  379. Return Value:
  380. RXSTATUS - The return status for the operation
  381. Notes:
  382. This routine will always be called. This is true even if the change directory
  383. notification is cancelled. In such cases the memory allocated is freed without
  384. any inteaction with the wrapper. In cases of successful directory change
  385. notification completion the appropriate completion routine is invoked and the
  386. RxContext modified to prevent any cancellation from proceeding further.
  387. --*/
  388. {
  389. NTSTATUS Status;
  390. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  391. PRX_CONTEXT pRxContext;
  392. PSMB_EXCHANGE pExchange = NULL;
  393. BOOLEAN FinalizeNotificationContext = FALSE;
  394. pRxContext = pNotificationContext->pRxContext;
  395. if (MRxSmbNonTrivialFileName(pRxContext))
  396. {
  397. MRxSmbInvalidateFullDirectoryCache(pRxContext);
  398. MRxSmbInvalidateFullDirectoryCacheParent(pRxContext,FALSE);
  399. }
  400. SmbCeAcquireSpinLock();
  401. FinalizeNotificationContext =
  402. (InterlockedDecrement(&pNotificationContext->ReferenceCount) == 0);
  403. if (pRxContext != NULL) {
  404. PSMB_TRANSACT_EXCHANGE pTransactExchange;
  405. pMRxSmbContext = MRxSmbGetMinirdrContext(pRxContext);
  406. pExchange = pMRxSmbContext->pExchange;
  407. if (pExchange != NULL) {
  408. PSMBCEDB_SERVER_ENTRY pServerEntry;
  409. pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  410. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  411. if ((pNotificationContext->ResumptionContext.FinalStatusFromServer ==
  412. STATUS_NOT_SUPPORTED) ||
  413. (pNotificationContext->ResumptionContext.FinalStatusFromServer ==
  414. STATUS_NOT_IMPLEMENTED)) {
  415. pServerEntry->Server.ChangeNotifyNotSupported = TRUE;
  416. }
  417. //
  418. // Validate the response buffer before returning.
  419. //
  420. if( pNotificationContext->ResumptionContext.FinalStatusFromServer == STATUS_SUCCESS ) {
  421. pNotificationContext->ResumptionContext.FinalStatusFromServer =
  422. FsRtlValidateChangeNotifyBuffer(
  423. pRxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer,
  424. pTransactExchange->ParamBytesReceived );
  425. }
  426. if( pNotificationContext->ResumptionContext.FinalStatusFromServer == STATUS_SUCCESS ) {
  427. pRxContext->InformationToReturn = pTransactExchange->ParamBytesReceived;
  428. } else {
  429. pRxContext->InformationToReturn = 0;
  430. }
  431. } else {
  432. pRxContext->InformationToReturn = 0;
  433. }
  434. pRxContext->StoredStatus =
  435. pNotificationContext->ResumptionContext.FinalStatusFromServer;
  436. if( (pRxContext->InformationToReturn == 0) &&
  437. (pRxContext->StoredStatus == STATUS_SUCCESS) )
  438. {
  439. pRxContext->StoredStatus = STATUS_NOTIFY_ENUM_DIR;
  440. //MRxSmbInvalidateFullDirectoryCache(pRxContext);
  441. }
  442. }
  443. SmbCeReleaseSpinLock();
  444. if (FinalizeNotificationContext) {
  445. if (pRxContext != NULL) {
  446. RxLowIoCompletion(pRxContext);
  447. }
  448. // Free the associated exchange.
  449. if (pExchange != NULL) {
  450. SmbCeDereferenceAndDiscardExchange(pExchange);
  451. }
  452. // Free the notification context.
  453. RxFreePool(pNotificationContext);
  454. }
  455. }
  456. NTSTATUS
  457. MRxSmbNotifyChangeDirectory(
  458. IN OUT PRX_CONTEXT RxContext)
  459. /*++
  460. Routine Description:
  461. This routine performs a directory change notification operation
  462. Arguments:
  463. RxContext - the RDBSS context
  464. Return Value:
  465. RXSTATUS - The return status for the operation
  466. Notes:
  467. A directory change notification opertaion is an asychronous operation. It
  468. consists of sending a SMB requesting change notification whose response is
  469. obtained when the desired change is affected on the server.
  470. Some important points to remember are as follows .....
  471. 1) The SMB response is not obtained till the desired change is affected on
  472. the server. Therefore an additional MID needs to be reserved on those
  473. connections which permit multiple MID's so that a cancel SMB can be sent to
  474. the server when a change notification is active.
  475. 2) The Change notification is typical of a long term ( response time
  476. dictated by factors beyond the servers control). Another example is
  477. the query FSCTL operation in CAIRO. For all these operations we initiate
  478. an asychronous transact exchange.
  479. 3) The corresponding LowIo completion routine is invoked asynchronously.
  480. 4) This is an example of an operation for which the MINI RDR has to
  481. register a context for handling cancellations initiated locally.
  482. --*/
  483. {
  484. NTSTATUS Status;
  485. RxCaptureFcb;
  486. RxCaptureFobx;
  487. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  488. PSMBCEDB_SERVER_ENTRY pServerEntry;
  489. PSMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext;
  490. PBYTE pInputParamBuffer = NULL;
  491. PBYTE pOutputParamBuffer = NULL;
  492. PBYTE pInputDataBuffer = NULL;
  493. PBYTE pOutputDataBuffer = NULL;
  494. ULONG InputParamBufferLength = 0;
  495. ULONG OutputParamBufferLength = 0;
  496. ULONG InputDataBufferLength = 0;
  497. ULONG OutputDataBufferLength = 0;
  498. RxDbgTrace(+1, Dbg, ("MRxNotifyChangeDirectory...Entry\n", 0));
  499. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  500. // if the server entry is in disconnected state, then let CSC do change notify
  501. // If successful, the CSC routine should return a STATUS_PENDING and
  502. // modify the rxcontext in way that is suitable to the underlying implementation
  503. // In the current incarnation, the CSC routine will
  504. // a) remove the irp from the rxconetxt and b) dereference the rxcontext
  505. if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)||
  506. SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  507. return MRxSmbCscNotifyChangeDirectory(RxContext);
  508. }
  509. else if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS) ||
  510. pServerEntry->Server.ChangeNotifyNotSupported) {
  511. return STATUS_NOT_SUPPORTED;
  512. }
  513. #if defined(REMOTE_BOOT)
  514. //
  515. // Reject change notify on the remote boot share. This is necessary to
  516. // prevent overloading the server with long-term requests. (There are
  517. // LOTS of change notifies posted on the boot device!)
  518. //
  519. if (MRxSmbBootedRemotely) {
  520. PSMBCE_SESSION pSession;
  521. pSession = &SmbCeGetAssociatedVNetRootContext(capFobx->pSrvOpen->pVNetRoot)->pSessionEntry->Session;
  522. if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
  523. return STATUS_NOT_SUPPORTED;
  524. }
  525. }
  526. #endif
  527. pNotificationContext =
  528. (PSMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT)
  529. RxAllocatePoolWithTag(
  530. NonPagedPool,
  531. sizeof(SMB_NOTIFY_CHANGE_DIRECTORY_CONTEXT),
  532. MRXSMB_FSCTL_POOLTAG);
  533. if (pNotificationContext != NULL) {
  534. PREQ_NOTIFY_CHANGE pNotifyRequest;
  535. PSMB_TRANSACTION_OPTIONS pTransactionOptions;
  536. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
  537. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  538. BOOLEAN FcbAcquired = FALSE;
  539. RxCaptureFobx;
  540. ASSERT (capFobx != NULL);
  541. if (!RxIsFcbAcquiredExclusive(capFcb)) {
  542. // ASSERT(!RxIsFcbAcquiredShared(capFcb));
  543. Status = RxAcquireExclusiveFcbResourceInMRx( capFcb );
  544. FcbAcquired = (Status == STATUS_SUCCESS);
  545. }
  546. if (FcbAcquired) {
  547. if (FlagOn(capFobx->pSrvOpen->Flags,SRVOPEN_FLAG_CLOSED) ||
  548. FlagOn(capFobx->pSrvOpen->Flags,SRVOPEN_FLAG_ORPHANED)) {
  549. Status = STATUS_FILE_CLOSED;
  550. } else {
  551. Status = MRxSmbDeferredCreate(RxContext);
  552. }
  553. RxReleaseFcbResourceInMRx( capFcb );
  554. }
  555. if (Status==STATUS_SUCCESS) {
  556. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  557. pNotificationContext->pRxContext = RxContext;
  558. // The reference count is set to 2. one for the async completion routine
  559. // and one for the tail completion routine
  560. pNotificationContext->ReferenceCount = 2;
  561. pNotifyRequest = &(pNotificationContext->NotifyRequest);
  562. pTransactionOptions = &(pNotificationContext->Options);
  563. pResumptionContext = &(pNotificationContext->ResumptionContext);
  564. pNotifyRequest->CompletionFilter = pLowIoContext->ParamsFor.NotifyChangeDirectory.CompletionFilter;
  565. pNotifyRequest->Fid = pSmbSrvOpen->Fid;
  566. pNotifyRequest->WatchTree = pLowIoContext->ParamsFor.NotifyChangeDirectory.WatchTree;
  567. pNotifyRequest->Reserved = 0;
  568. OutputParamBufferLength = pLowIoContext->ParamsFor.NotifyChangeDirectory.NotificationBufferLength;
  569. pOutputParamBuffer = pLowIoContext->ParamsFor.NotifyChangeDirectory.pNotificationBuffer;
  570. *pTransactionOptions = RxDefaultTransactionOptions;
  571. pTransactionOptions->NtTransactFunction = NT_TRANSACT_NOTIFY_CHANGE;
  572. pTransactionOptions->TimeoutIntervalInMilliSeconds = SMBCE_TRANSACTION_TIMEOUT_NOT_USED;
  573. pTransactionOptions->Flags = SMB_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE;
  574. SmbCeInitializeAsynchronousTransactionResumptionContext(
  575. pResumptionContext,
  576. MRxSmbNotifyChangeDirectoryCompletion,
  577. pNotificationContext);
  578. Status = SmbCeAsynchronousTransact(
  579. RxContext, // the RXContext for the transaction
  580. pTransactionOptions, // transaction options
  581. pNotifyRequest, // the setup buffer
  582. sizeof(REQ_NOTIFY_CHANGE), // setup buffer length
  583. NULL,
  584. 0,
  585. pInputParamBuffer, // Input Param Buffer
  586. InputParamBufferLength, // Input param buffer length
  587. pOutputParamBuffer, // Output param buffer
  588. OutputParamBufferLength, // output param buffer length
  589. pInputDataBuffer, // Input data buffer
  590. InputDataBufferLength, // Input data buffer length
  591. pOutputDataBuffer, // output data buffer
  592. OutputDataBufferLength, // output data buffer length
  593. pResumptionContext // the resumption context
  594. );
  595. ASSERT(Status == STATUS_PENDING);
  596. Status = MRxSmbNotifyChangeDirectorySynchronousCompletion(
  597. pNotificationContext);
  598. } else {
  599. NOTHING; //just return the status from the deferred open call
  600. }
  601. } else {
  602. Status = STATUS_INSUFFICIENT_RESOURCES;
  603. }
  604. if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)||
  605. SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  606. return MRxSmbCscNotifyChangeDirectory(RxContext);
  607. }
  608. RxDbgTrace(-1, Dbg, ("MRxSmbNotifyChangeDirectory -> %08lx\n", Status ));
  609. return Status;
  610. }
  611. UNICODE_STRING s_NamedPipeTransactionName = { 12,12,L"\\PIPE\\" };
  612. UNICODE_STRING s_MailSlotTransactionName = {20,20,L"\\MAILSLOT\\" };
  613. typedef struct _SMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT_ {
  614. LONG ReferenceCount;
  615. PRX_CONTEXT pRxContext;
  616. PWCHAR pTransactionNameBuffer;
  617. SMB_TRANSACTION_OPTIONS Options;
  618. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  619. } SMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT,
  620. *PSMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT;
  621. VOID
  622. MRxSmbNamedPipeFsControlCompletion(
  623. PSMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT pFsCtlCompletionContext)
  624. {
  625. PRX_CONTEXT pRxContext = NULL;
  626. PSMB_EXCHANGE pExchange = NULL;
  627. BOOLEAN FinalizeFsCtlCompletionContext = FALSE;
  628. SmbCeAcquireSpinLock();
  629. FinalizeFsCtlCompletionContext =
  630. (InterlockedDecrement(&pFsCtlCompletionContext->ReferenceCount) == 0);
  631. if (FinalizeFsCtlCompletionContext) {
  632. pRxContext = pFsCtlCompletionContext->pRxContext;
  633. if (pRxContext != NULL) {
  634. PMRXSMB_RX_CONTEXT pMRxSmbContext;
  635. pMRxSmbContext = MRxSmbGetMinirdrContext(pRxContext);
  636. pExchange = pMRxSmbContext->pExchange;
  637. }
  638. }
  639. SmbCeReleaseSpinLock();
  640. if (FinalizeFsCtlCompletionContext) {
  641. if (pRxContext != NULL) {
  642. pRxContext->StoredStatus =
  643. pFsCtlCompletionContext->ResumptionContext.FinalStatusFromServer;
  644. if (pRxContext->StoredStatus == STATUS_INVALID_HANDLE) {
  645. pRxContext->StoredStatus = STATUS_INVALID_NETWORK_RESPONSE;
  646. }
  647. pRxContext->InformationToReturn =
  648. pFsCtlCompletionContext->ResumptionContext.DataBytesReceived;
  649. RxLowIoCompletion(pRxContext);
  650. }
  651. if (pExchange != NULL) {
  652. SmbCeDereferenceAndDiscardExchange(pExchange);
  653. }
  654. if (pFsCtlCompletionContext->pTransactionNameBuffer != NULL) {
  655. RxFreePool(pFsCtlCompletionContext->pTransactionNameBuffer);
  656. }
  657. RxFreePool(pFsCtlCompletionContext);
  658. }
  659. }
  660. NTSTATUS
  661. MRxSmbNamedPipeFsControl(PRX_CONTEXT RxContext)
  662. /*++
  663. Routine Description:
  664. This routine handles all named pipe related FSCTL's
  665. Arguments:
  666. RxContext - the RDBSS context
  667. Return Value:
  668. RXSTATUS - The return status for the operation
  669. --*/
  670. {
  671. RxCaptureFobx;
  672. RxCaptureFcb;
  673. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  674. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  675. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  676. UNICODE_STRING TransactionName;
  677. BOOLEAN ReestablishConnectionIfRequired = FALSE, fTransactioNameBufferAllocated = FALSE;
  678. NTSTATUS Status;
  679. USHORT Setup[2];
  680. PBYTE pInputParamBuffer = NULL;
  681. PBYTE pOutputParamBuffer = NULL;
  682. PBYTE pInputDataBuffer = NULL;
  683. PBYTE pOutputDataBuffer = NULL;
  684. ULONG InputParamBufferLength = 0;
  685. ULONG OutputParamBufferLength = 0;
  686. ULONG InputDataBufferLength = 0;
  687. ULONG OutputDataBufferLength = 0;
  688. ULONG TimeoutIntervalInMilliSeconds;
  689. RESP_PEEK_NMPIPE PeekResponse;
  690. KAPC_STATE ApcState;
  691. PAGED_CODE();
  692. RxDbgTrace(+1, Dbg, ("MRxSmbNamedPipeFsControl...\n", 0));
  693. TimeoutIntervalInMilliSeconds = SMBCE_TRANSACTION_TIMEOUT_NOT_USED;
  694. Status = STATUS_MORE_PROCESSING_REQUIRED;
  695. if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_FILE &&
  696. NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN ||
  697. capFcb->pNetRoot == NULL ||
  698. capFcb->pNetRoot->Type != NET_ROOT_PIPE) {
  699. return STATUS_INVALID_DEVICE_REQUEST;
  700. }
  701. if (capFobx != NULL) {
  702. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  703. } else {
  704. pSmbSrvOpen = NULL;
  705. }
  706. //
  707. // FSCTLs which use method_neither must be called in the context of the calling process.
  708. //
  709. KeStackAttachProcess (IoGetRequestorProcess(RxContext->CurrentIrp), &ApcState);
  710. // The following switch statement serves the dual purpose of validating the parameters
  711. // presented by the user as well as filling in the appropriate information if it is
  712. // available locally.
  713. // Currently there is no local caching strategy in place and consequently a network trip
  714. // is always undertaken.
  715. TransactionName = s_NamedPipeTransactionName;
  716. switch (FsControlCode) {
  717. case FSCTL_PIPE_PEEK :
  718. {
  719. Setup[0] = TRANS_PEEK_NMPIPE;
  720. Setup[1] = pSmbSrvOpen->Fid;
  721. pOutputParamBuffer = (PBYTE)&PeekResponse;
  722. OutputParamBufferLength = sizeof(PeekResponse);
  723. pOutputDataBuffer = (PBYTE)pLowIoContext->ParamsFor.FsCtl.pOutputBuffer +
  724. FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER,Data[0]);
  725. OutputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.OutputBufferLength -
  726. FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER,Data[0]);
  727. if ((pLowIoContext->ParamsFor.FsCtl.pOutputBuffer != NULL) &&
  728. (pLowIoContext->ParamsFor.FsCtl.OutputBufferLength < (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER,Data[0]))) {
  729. Status = STATUS_BUFFER_TOO_SMALL;
  730. }
  731. }
  732. break;
  733. case FSCTL_PIPE_TRANSCEIVE :
  734. {
  735. Setup[0] = TRANS_TRANSACT_NMPIPE;
  736. Setup[1] = pSmbSrvOpen->Fid;
  737. pInputDataBuffer = pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  738. InputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.InputBufferLength;
  739. pOutputDataBuffer = pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  740. OutputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  741. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  742. try {
  743. if (pInputDataBuffer) {
  744. ProbeForRead(pInputDataBuffer,InputDataBufferLength,1);
  745. }
  746. if (pOutputDataBuffer) {
  747. ProbeForWrite(pOutputDataBuffer,OutputDataBufferLength,1);
  748. }
  749. } except (EXCEPTION_EXECUTE_HANDLER) {
  750. Status=STATUS_INVALID_PARAMETER;
  751. }
  752. }
  753. // CODE.IMPROVEMENT -- Currently the semantics of attempting a TRANSCEIVE
  754. // with zero bytes to be written is not very well defined. The Old Redirector
  755. // succeeds without issuing a TRANSACT request. This needs to be resolved and
  756. // till it is done the old semantics will be retained
  757. //if (InputDataBufferLength == 0) {
  758. // Status = STATUS_SUCCESS;
  759. //}
  760. }
  761. break;
  762. case FSCTL_PIPE_WAIT :
  763. {
  764. PFILE_PIPE_WAIT_FOR_BUFFER pWaitBuffer;
  765. ULONG NameLength;
  766. Setup[0] = TRANS_WAIT_NMPIPE;
  767. Setup[1] = 0;
  768. if ((pLowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
  769. (pLowIoContext->ParamsFor.FsCtl.InputBufferLength <
  770. sizeof(FILE_PIPE_WAIT_FOR_BUFFER))) {
  771. Status = STATUS_INVALID_PARAMETER;
  772. } else {
  773. // Set up the transaction name to reflect the name of the pipe
  774. // on which the wait operation is being performed.
  775. pWaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  776. if (pWaitBuffer->NameLength + s_NamedPipeTransactionName.Length > MAXUSHORT ||
  777. pWaitBuffer->NameLength - sizeof(WCHAR) >
  778. pLowIoContext->ParamsFor.FsCtl.InputBufferLength - sizeof(FILE_PIPE_WAIT_FOR_BUFFER)) {
  779. // if the name is too long to be put on a UNICIDE string,
  780. // or the name length doesn't match the buffer length
  781. Status = STATUS_INVALID_PARAMETER;
  782. }
  783. }
  784. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  785. // In the case of Wait FSCTL a reconnection attempt will be made
  786. // if required
  787. ReestablishConnectionIfRequired = TRUE;
  788. TransactionName.Length = (USHORT)(s_NamedPipeTransactionName.Length +
  789. pWaitBuffer->NameLength);
  790. TransactionName.MaximumLength = TransactionName.Length;
  791. TransactionName.Buffer = (PWCHAR)RxAllocatePool(PagedPool,TransactionName.Length);
  792. if (TransactionName.Buffer != NULL) {
  793. fTransactioNameBufferAllocated = TRUE;
  794. RtlCopyMemory(TransactionName.Buffer,
  795. s_NamedPipeTransactionName.Buffer,
  796. s_NamedPipeTransactionName.Length);
  797. RtlCopyMemory(
  798. (PBYTE)TransactionName.Buffer + s_NamedPipeTransactionName.Length,
  799. pWaitBuffer->Name,
  800. pWaitBuffer->NameLength);
  801. } else {
  802. Status = STATUS_INSUFFICIENT_RESOURCES;
  803. }
  804. if (pWaitBuffer->TimeoutSpecified) {
  805. LARGE_INTEGER TimeWorkspace;
  806. LARGE_INTEGER WaitForever;
  807. WaitForever.LowPart = 0;
  808. WaitForever.HighPart =0x80000000;
  809. // Avoid negate of "WaitForever" since this generates an integer
  810. // overflow exception on some machines.
  811. if (pWaitBuffer->Timeout.QuadPart != WaitForever.QuadPart) {
  812. TimeWorkspace.QuadPart = -pWaitBuffer->Timeout.QuadPart / 10000;
  813. if ( TimeWorkspace.HighPart) {
  814. // Tried to specify a larger timeout than we can select.
  815. // set it to the Maximum we can request
  816. TimeoutIntervalInMilliSeconds = 0xfffffffe;
  817. } else {
  818. TimeoutIntervalInMilliSeconds = TimeWorkspace.LowPart;
  819. }
  820. }
  821. } else {
  822. TimeoutIntervalInMilliSeconds = 0;
  823. }
  824. }
  825. }
  826. break;
  827. case FSCTL_PIPE_ASSIGN_EVENT :
  828. case FSCTL_PIPE_QUERY_EVENT :
  829. case FSCTL_PIPE_IMPERSONATE :
  830. case FSCTL_PIPE_SET_CLIENT_PROCESS :
  831. case FSCTL_PIPE_QUERY_CLIENT_PROCESS :
  832. // These FSCTL's have not been implemented so far in NT. They will be implemented
  833. // in a future release.
  834. Status = STATUS_INVALID_PARAMETER;
  835. RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl: Unimplemented FS control code\n"));
  836. break;
  837. case FSCTL_PIPE_DISCONNECT :
  838. case FSCTL_PIPE_LISTEN :
  839. Status = STATUS_INVALID_PARAMETER;
  840. RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl: Invalid FS control code for redirector\n"));
  841. break;
  842. default:
  843. RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl: Invalid FS control code\n"));
  844. Status = STATUS_INVALID_PARAMETER;
  845. break;
  846. }
  847. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  848. if (ReestablishConnectionIfRequired) {
  849. if (capFobx != NULL) {
  850. Status = SmbCeReconnect(capFobx->pSrvOpen->pVNetRoot);
  851. } else {
  852. Status = STATUS_SUCCESS;
  853. }
  854. } else {
  855. Status = STATUS_SUCCESS;
  856. }
  857. if (Status == STATUS_SUCCESS) {
  858. PSMB_TRANSACTION_OPTIONS pTransactionOptions;
  859. PSMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT pFsCtlCompletionContext;
  860. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
  861. RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl: TransactionName %ws Length %ld\n",
  862. TransactionName.Buffer,TransactionName.Length));
  863. pFsCtlCompletionContext =
  864. (PSMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT)
  865. RxAllocatePoolWithTag(
  866. NonPagedPool,
  867. sizeof(SMB_NAMED_PIPE_FSCTL_COMPLETION_CONTEXT),
  868. MRXSMB_FSCTL_POOLTAG);
  869. if (pFsCtlCompletionContext != NULL) {
  870. pResumptionContext = &pFsCtlCompletionContext->ResumptionContext;
  871. pTransactionOptions = &(pFsCtlCompletionContext->Options);
  872. if (FsControlCode != FSCTL_PIPE_PEEK) {
  873. // The reference count is set to 2. one for the async
  874. // completion routine and one for the tail completion routine
  875. pFsCtlCompletionContext->pRxContext = RxContext;
  876. pFsCtlCompletionContext->ReferenceCount = 2;
  877. SmbCeInitializeAsynchronousTransactionResumptionContext(
  878. pResumptionContext,
  879. MRxSmbNamedPipeFsControlCompletion,
  880. pFsCtlCompletionContext);
  881. } else {
  882. // Currently PEEK operations are synchronous
  883. pFsCtlCompletionContext->pRxContext = NULL;
  884. pFsCtlCompletionContext->ReferenceCount = 1;
  885. }
  886. *pTransactionOptions = RxDefaultTransactionOptions;
  887. pTransactionOptions->NtTransactFunction = 0; // TRANSACT2/TRANSACT.
  888. pTransactionOptions->pTransactionName = &TransactionName;
  889. pTransactionOptions->Flags = SMB_XACT_FLAGS_FID_NOT_NEEDED;
  890. pTransactionOptions->TimeoutIntervalInMilliSeconds = TimeoutIntervalInMilliSeconds;
  891. if (TransactionName.Buffer != s_NamedPipeTransactionName.Buffer) {
  892. pFsCtlCompletionContext->pTransactionNameBuffer =
  893. TransactionName.Buffer;
  894. } else {
  895. pFsCtlCompletionContext->pTransactionNameBuffer = NULL;
  896. }
  897. if (FsControlCode != FSCTL_PIPE_PEEK) {
  898. Status = SmbCeAsynchronousTransact(
  899. RxContext, // the RXContext for the transaction
  900. pTransactionOptions, // transaction options
  901. Setup, // the setup buffer
  902. sizeof(Setup), // setup buffer length
  903. NULL,
  904. 0,
  905. pInputParamBuffer, // Input Param Buffer
  906. InputParamBufferLength, // Input param buffer length
  907. pOutputParamBuffer, // Output param buffer
  908. OutputParamBufferLength, // output param buffer length
  909. pInputDataBuffer, // Input data buffer
  910. InputDataBufferLength, // Input data buffer length
  911. pOutputDataBuffer, // output data buffer
  912. OutputDataBufferLength, // output data buffer length
  913. pResumptionContext // the resumption context
  914. );
  915. if (Status != STATUS_PENDING) {
  916. pFsCtlCompletionContext->ResumptionContext.FinalStatusFromServer
  917. = Status;
  918. }
  919. MRxSmbNamedPipeFsControlCompletion(pFsCtlCompletionContext);
  920. Status = STATUS_PENDING;
  921. } else {
  922. Status = SmbCeTransact(
  923. RxContext, // the RXContext for the transaction
  924. pTransactionOptions, // transaction options
  925. Setup, // the setup buffer
  926. sizeof(Setup), // setup buffer length
  927. NULL,
  928. 0,
  929. pInputParamBuffer, // Input Param Buffer
  930. InputParamBufferLength, // Input param buffer length
  931. pOutputParamBuffer, // Output param buffer
  932. OutputParamBufferLength, // output param buffer length
  933. pInputDataBuffer, // Input data buffer
  934. InputDataBufferLength, // Input data buffer length
  935. pOutputDataBuffer, // output data buffer
  936. OutputDataBufferLength, // output data buffer length
  937. pResumptionContext // the resumption context
  938. );
  939. switch (FsControlCode) {
  940. case FSCTL_PIPE_PEEK:
  941. {
  942. // In the case of FSCTL_PIPE_PEEK post processing is required to package the
  943. // results and also handle the idiosyncracies of the different servers.
  944. // e.g.,
  945. // Os/2 servers will allow PeekNamedPipe on closed pipes to succeed
  946. // even if the server side of the pipe is closed.
  947. //
  948. // If we get the status PIPE_STATE_CLOSING from the server, then
  949. // we need to return an error of STATUS_PIPE_DISCONNECTED, as this
  950. // is what NPFS will do.
  951. if (NT_SUCCESS(Status) ||
  952. (Status == RX_MAP_STATUS(BUFFER_OVERFLOW))) {
  953. if (pResumptionContext->ParameterBytesReceived >= sizeof(RESP_PEEK_NMPIPE)) {
  954. if ((SmbGetAlignedUshort(&PeekResponse.NamedPipeState) & PIPE_STATE_CLOSING) &&
  955. (PeekResponse.ReadDataAvailable == 0)) {
  956. Status = STATUS_PIPE_DISCONNECTED;
  957. } else {
  958. PFILE_PIPE_PEEK_BUFFER pPeekBuffer;
  959. pPeekBuffer = (PFILE_PIPE_PEEK_BUFFER)pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  960. pPeekBuffer->NamedPipeState = (ULONG)SmbGetAlignedUshort(&PeekResponse.NamedPipeState);
  961. pPeekBuffer->ReadDataAvailable = (ULONG)PeekResponse.ReadDataAvailable;
  962. pPeekBuffer->NumberOfMessages = MAXULONG;
  963. pPeekBuffer->MessageLength = (ULONG)PeekResponse.MessageLength;
  964. if (PeekResponse.MessageLength > OutputDataBufferLength) {
  965. Status = STATUS_BUFFER_OVERFLOW;
  966. }
  967. }
  968. }
  969. RxContext->InformationToReturn =
  970. FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]) +
  971. pResumptionContext->DataBytesReceived;
  972. }
  973. }
  974. break;
  975. default:
  976. RxContext->InformationToReturn =
  977. pResumptionContext->DataBytesReceived;
  978. break;
  979. }
  980. MRxSmbNamedPipeFsControlCompletion(pFsCtlCompletionContext);
  981. }
  982. } else {
  983. if (fTransactioNameBufferAllocated)
  984. {
  985. RxFreePool(TransactionName.Buffer);
  986. }
  987. Status = STATUS_INSUFFICIENT_RESOURCES;
  988. }
  989. }
  990. }
  991. if (!NT_SUCCESS(Status)) {
  992. if (Status == STATUS_INVALID_HANDLE) {
  993. Status = STATUS_INVALID_NETWORK_RESPONSE;
  994. }
  995. RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl(%ld): Failed .. returning %lx\n",FsControlCode,Status));
  996. }
  997. //
  998. // Detach from caller process
  999. //
  1000. KeUnstackDetachProcess(&ApcState);
  1001. RxDbgTrace(-1, Dbg, ("MRxSmbNamedPipeFsControl exit...st=%08lx\n", Status));
  1002. return Status;
  1003. }
  1004. #ifdef _WIN64
  1005. typedef struct _LMR_TRANSACTION_32 {
  1006. ULONG Type; // Type of structure
  1007. ULONG Size; // Size of fixed portion of structure
  1008. ULONG Version; // Structure version.
  1009. ULONG NameLength; // Number of bytes in name (in path
  1010. // format, e.g., \server\pipe\netapi\4)
  1011. ULONG NameOffset; // Offset of name in buffer.
  1012. BOOLEAN ResponseExpected; // Should remote system respond?
  1013. ULONG Timeout; // Timeout time in milliseconds.
  1014. ULONG SetupWords; // Number of trans setup words (may be
  1015. // 0). (setup words are input/output.)
  1016. ULONG SetupOffset; // Offset of setup (may be 0 for none).
  1017. ULONG MaxSetup; // Size of setup word array (may be 0).
  1018. ULONG ParmLength; // Input param area length (may be 0).
  1019. void * POINTER_32 ParmPtr; // Input parameter area (may be NULL).
  1020. ULONG MaxRetParmLength; // Output param. area length (may be 0).
  1021. ULONG DataLength; // Input data area length (may be 0).
  1022. void * POINTER_32 DataPtr; // Input data area (may be NULL).
  1023. ULONG MaxRetDataLength; // Output data area length (may be 0).
  1024. void * POINTER_32 RetDataPtr; // Output data area (may be NULL).
  1025. } LMR_TRANSACTION_32, *PLMR_TRANSACTION_32;
  1026. #endif
  1027. NTSTATUS
  1028. MRxSmbFsCtlUserTransact(PRX_CONTEXT RxContext)
  1029. /*++
  1030. Routine Description:
  1031. This routine issues what is called a UserTransaction against the server that is serving the
  1032. connection for this file. very strange.............
  1033. Arguments:
  1034. RxContext - the RDBSS context
  1035. Return Value:
  1036. RXSTATUS - The return status for the operation
  1037. --*/
  1038. {
  1039. RxCaptureFobx;
  1040. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1041. UNICODE_STRING TransactionName;
  1042. LMR_TRANSACTION InputBuffer;
  1043. ULONG InputBufferLength = pLowIoContext->ParamsFor.FsCtl.InputBufferLength;
  1044. ULONG SizeOfLmrTransaction = 0;
  1045. NTSTATUS Status;
  1046. PAGED_CODE();
  1047. if( pLowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL )
  1048. {
  1049. return (Status = STATUS_INVALID_PARAMETER);
  1050. }
  1051. InputBuffer = *((PLMR_TRANSACTION)pLowIoContext->ParamsFor.FsCtl.pInputBuffer);
  1052. #ifdef _WIN64
  1053. if (IoIs32bitProcess(RxContext->CurrentIrp)) {
  1054. PLMR_TRANSACTION_32 InputBuffer32 = (PLMR_TRANSACTION_32)pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1055. if (InputBufferLength < sizeof(LMR_TRANSACTION_32)) {
  1056. return STATUS_INVALID_PARAMETER;
  1057. }
  1058. InputBuffer.Type = InputBuffer32->Type;
  1059. InputBuffer.Size = InputBuffer32->Size;
  1060. InputBuffer.Version = InputBuffer32->Version;
  1061. InputBuffer.NameLength = InputBuffer32->NameLength;
  1062. InputBuffer.NameOffset = InputBuffer32->NameOffset;
  1063. InputBuffer.ResponseExpected = InputBuffer32->ResponseExpected;
  1064. InputBuffer.Timeout = InputBuffer32->Timeout;
  1065. InputBuffer.SetupWords = InputBuffer32->SetupWords;
  1066. InputBuffer.SetupOffset = InputBuffer32->SetupOffset;
  1067. InputBuffer.MaxSetup = InputBuffer32->MaxSetup;
  1068. InputBuffer.ParmLength = InputBuffer32->ParmLength;
  1069. InputBuffer.ParmPtr = (PVOID)InputBuffer32->ParmPtr;
  1070. InputBuffer.MaxRetParmLength = InputBuffer32->MaxRetParmLength;
  1071. InputBuffer.DataLength = InputBuffer32->DataLength;
  1072. InputBuffer.DataPtr = (PVOID)InputBuffer32->DataPtr;
  1073. InputBuffer.MaxRetDataLength = InputBuffer32->MaxRetDataLength;
  1074. InputBuffer.RetDataPtr = (PVOID)InputBuffer32->RetDataPtr;
  1075. SizeOfLmrTransaction = sizeof(LMR_TRANSACTION_32);
  1076. } else {
  1077. SizeOfLmrTransaction = sizeof(LMR_TRANSACTION);
  1078. }
  1079. #else
  1080. SizeOfLmrTransaction = sizeof(LMR_TRANSACTION);
  1081. #endif
  1082. RxDbgTrace(+1, Dbg, ("MRxSmbFsCtlUserTransact...\n"));
  1083. if (InputBufferLength < SizeOfLmrTransaction) {
  1084. return(Status = STATUS_INVALID_PARAMETER);
  1085. }
  1086. if (InputBufferLength - SizeOfLmrTransaction < InputBuffer.NameLength) {
  1087. return(Status = STATUS_BUFFER_TOO_SMALL);
  1088. }
  1089. if ((InputBuffer.Type != TRANSACTION_REQUEST) ||
  1090. (InputBuffer.Version != TRANSACTION_VERSION)) {
  1091. return(Status = STATUS_INVALID_PARAMETER);
  1092. }
  1093. if (InputBuffer.NameOffset + InputBuffer.NameLength > InputBufferLength) {
  1094. return(Status = STATUS_INVALID_PARAMETER);
  1095. }
  1096. if (InputBuffer.SetupOffset + InputBuffer.SetupWords > InputBufferLength) {
  1097. return(Status = STATUS_INVALID_PARAMETER);
  1098. }
  1099. if (capFobx != NULL) {
  1100. PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  1101. if (NodeType(pVNetRoot) == RDBSS_NTC_V_NETROOT) {
  1102. Status = SmbCeReconnect(pVNetRoot);
  1103. } else {
  1104. Status = SmbCeReconnect(capFobx->pSrvOpen->pVNetRoot);
  1105. }
  1106. if (Status != STATUS_SUCCESS) {
  1107. return Status;
  1108. }
  1109. }
  1110. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1111. TransactionName.MaximumLength = (USHORT)InputBuffer.NameLength;
  1112. TransactionName.Length = (USHORT)InputBuffer.NameLength;
  1113. TransactionName.Buffer = (PWSTR)(((PUCHAR)pLowIoContext->ParamsFor.FsCtl.pInputBuffer)+InputBuffer.NameOffset);
  1114. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1115. SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
  1116. SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
  1117. SMB_TRANSACTION_OPTIONS TransactionOptions = RxDefaultTransactionOptions;
  1118. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1119. PUCHAR SetupBuffer = NULL;
  1120. RxDbgTrace( 0, Dbg, ("MRxSmbFsCtlUserTransact: TransactionName %ws Length %ld\n",
  1121. TransactionName.Buffer,TransactionName.Length));
  1122. TransactionOptions.NtTransactFunction = 0; // TRANSACT2/TRANSACT.
  1123. TransactionOptions.pTransactionName = &TransactionName;
  1124. TransactionOptions.Flags = SMB_XACT_FLAGS_FID_NOT_NEEDED;
  1125. if (!InputBuffer.ResponseExpected) {
  1126. TransactionOptions.Flags |= SMB_TRANSACTION_NO_RESPONSE;
  1127. }
  1128. TransactionOptions.TimeoutIntervalInMilliSeconds = InputBuffer.Timeout;
  1129. SmbCeInitializeTransactionResumptionContext(&ResumptionContext);
  1130. try {
  1131. if (InputBuffer.SetupOffset){
  1132. SetupBuffer = (PUCHAR)pLowIoContext->ParamsFor.FsCtl.pInputBuffer+InputBuffer.SetupOffset;
  1133. }
  1134. if (SetupBuffer) {
  1135. ProbeForWrite(SetupBuffer,InputBuffer.MaxSetup,1);
  1136. }
  1137. if (InputBuffer.ParmPtr) {
  1138. ProbeForWrite(InputBuffer.ParmPtr,InputBuffer.MaxRetParmLength,1);
  1139. }
  1140. if (InputBuffer.RetDataPtr) {
  1141. ProbeForWrite(InputBuffer.RetDataPtr,InputBuffer.MaxRetDataLength,1);
  1142. }
  1143. } except(EXCEPTION_EXECUTE_HANDLER) {
  1144. return STATUS_INVALID_PARAMETER;
  1145. }
  1146. Status = SmbCeTransact(
  1147. RxContext,
  1148. &TransactionOptions,
  1149. SetupBuffer,
  1150. (USHORT)InputBuffer.SetupWords,
  1151. SetupBuffer,
  1152. InputBuffer.MaxSetup,
  1153. InputBuffer.ParmPtr,
  1154. InputBuffer.ParmLength,
  1155. InputBuffer.ParmPtr, // the buffer for the param information
  1156. InputBuffer.MaxRetParmLength,// the length of the param buffer
  1157. InputBuffer.DataPtr,
  1158. InputBuffer.DataLength,
  1159. InputBuffer.RetDataPtr, // the buffer for data
  1160. InputBuffer.MaxRetDataLength,// the length of the buffer
  1161. &ResumptionContext);
  1162. if (NT_SUCCESS(Status)) {
  1163. //LowIoContext->ParamsFor.FsCtl.OutputBufferLength = ResumptionContext.DataBytesReceived;
  1164. #ifdef _WIN64
  1165. if (IoIs32bitProcess(RxContext->CurrentIrp)) {
  1166. PLMR_TRANSACTION_32 pInputBuffer = (PLMR_TRANSACTION_32)pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1167. pInputBuffer->MaxRetParmLength = ResumptionContext.ParameterBytesReceived;
  1168. pInputBuffer->MaxRetDataLength = ResumptionContext.DataBytesReceived;
  1169. pInputBuffer->MaxSetup = ResumptionContext.SetupBytesReceived;
  1170. //this seems like a bad return value for iostatus.information
  1171. RxContext->InformationToReturn = SizeOfLmrTransaction + pInputBuffer->SetupWords;
  1172. } else {
  1173. PLMR_TRANSACTION pInputBuffer = (PLMR_TRANSACTION)pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1174. pInputBuffer->MaxRetParmLength = ResumptionContext.ParameterBytesReceived;
  1175. pInputBuffer->MaxRetDataLength = ResumptionContext.DataBytesReceived;
  1176. pInputBuffer->MaxSetup = ResumptionContext.SetupBytesReceived;
  1177. //this seems like a return value for iostatus.information
  1178. RxContext->InformationToReturn = SizeOfLmrTransaction + pInputBuffer->SetupWords;
  1179. }
  1180. #else
  1181. {
  1182. PLMR_TRANSACTION pInputBuffer = (PLMR_TRANSACTION)pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1183. pInputBuffer->MaxRetParmLength = ResumptionContext.ParameterBytesReceived;
  1184. pInputBuffer->MaxRetDataLength = ResumptionContext.DataBytesReceived;
  1185. pInputBuffer->MaxSetup = ResumptionContext.SetupBytesReceived;
  1186. //this seems like a return value for iostatus.information
  1187. RxContext->InformationToReturn = SizeOfLmrTransaction + pInputBuffer->SetupWords;
  1188. }
  1189. #endif
  1190. }
  1191. }
  1192. if (!NT_SUCCESS(Status)) {
  1193. RxDbgTrace( 0, Dbg, ("MRxSmbFsCtlUserTransact: Failed .. returning %lx\n",Status));
  1194. }
  1195. RxDbgTrace(-1, Dbg, ("MRxSmbFsCtlUserTransact exit...st=%08lx\n", Status));
  1196. return Status;
  1197. }
  1198. NTSTATUS
  1199. MRxSmbMailSlotFsControl(PRX_CONTEXT RxContext)
  1200. /*++
  1201. Routine Description:
  1202. This routine handles all named pipe related FSCTL's
  1203. Arguments:
  1204. RxContext - the RDBSS context
  1205. Return Value:
  1206. RXSTATUS - The return status for the operation
  1207. --*/
  1208. {
  1209. PAGED_CODE();
  1210. return STATUS_NOT_IMPLEMENTED;
  1211. }
  1212. NTSTATUS
  1213. MRxSmbDfsFsControl(PRX_CONTEXT RxContext)
  1214. /*++
  1215. Routine Description:
  1216. This routine handles all DFS related FSCTL's
  1217. Arguments:
  1218. RxContext - the RDBSS context
  1219. Return Value:
  1220. RXSTATUS - The return status for the operation
  1221. --*/
  1222. {
  1223. RxCaptureFobx;
  1224. RxCaptureFcb;
  1225. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  1226. SMB_TRANSACTION_OPTIONS TransactionOptions = DEFAULT_TRANSACTION_OPTIONS;
  1227. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1228. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1229. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  1230. NTSTATUS Status;
  1231. USHORT Setup;
  1232. PBYTE pInputParamBuffer = NULL;
  1233. PBYTE pOutputParamBuffer = NULL;
  1234. PBYTE pInputDataBuffer = NULL;
  1235. PBYTE pOutputDataBuffer = NULL;
  1236. ULONG InputParamBufferLength = 0;
  1237. ULONG OutputParamBufferLength = 0;
  1238. ULONG InputDataBufferLength = 0;
  1239. ULONG OutputDataBufferLength = 0;
  1240. PAGED_CODE();
  1241. RxDbgTrace(+1, Dbg, ("MRxSmbDfsFsControl...\n", 0));
  1242. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  1243. // these FSCTLS are only su[pported from a kernel mode component
  1244. // because of parameter validation issues
  1245. return STATUS_INVALID_DEVICE_REQUEST;
  1246. }
  1247. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1248. if (capFobx != NULL) {
  1249. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  1250. } else {
  1251. pSmbSrvOpen = NULL;
  1252. }
  1253. pInputParamBuffer = pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1254. InputParamBufferLength = pLowIoContext->ParamsFor.FsCtl.InputBufferLength;
  1255. switch (FsControlCode) {
  1256. case FSCTL_DFS_GET_REFERRALS:
  1257. {
  1258. pOutputDataBuffer = pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  1259. OutputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  1260. }
  1261. break;
  1262. case FSCTL_DFS_REPORT_INCONSISTENCY:
  1263. {
  1264. PWCHAR pDfsPathName;
  1265. //
  1266. // The input buffer from Dfs contains the path name with the inconsistency
  1267. // followed by the DFS_REFERRAL_V1 that has the inconsistency. The
  1268. // path name is sent in the Parameter section, and the DFS_REFERRAL_V1 is
  1269. // passed in the Data section. So, parse these two things out.
  1270. //
  1271. for (pDfsPathName = (PWCHAR) pInputParamBuffer;
  1272. *pDfsPathName != UNICODE_NULL && pDfsPathName < (PWCHAR)pInputParamBuffer+InputParamBufferLength/sizeof(WCHAR);
  1273. pDfsPathName++) {
  1274. NOTHING;
  1275. }
  1276. pDfsPathName++; // Get past the NULL char
  1277. InputParamBufferLength = (ULONG) (((PCHAR)pDfsPathName) - ((PCHAR)pInputParamBuffer));
  1278. if (InputParamBufferLength >= pLowIoContext->ParamsFor.FsCtl.InputBufferLength) {
  1279. Status = STATUS_INVALID_PARAMETER;
  1280. } else {
  1281. pInputDataBuffer = (PBYTE)pDfsPathName;
  1282. InputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.InputBufferLength -
  1283. InputParamBufferLength;
  1284. }
  1285. }
  1286. break;
  1287. default:
  1288. ASSERT(!"Valid Dfs FSCTL");
  1289. }
  1290. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1291. Setup = TRANS2_GET_DFS_REFERRAL;
  1292. TransactionOptions.NtTransactFunction = 0; // TRANSACT2/TRANSACT.
  1293. TransactionOptions.pTransactionName = NULL;
  1294. TransactionOptions.TimeoutIntervalInMilliSeconds = SMBCE_TRANSACTION_TIMEOUT_NOT_USED;
  1295. Status = SmbCeTransact(
  1296. RxContext, // the RXContext for the transaction
  1297. &TransactionOptions, // transaction options
  1298. &Setup, // the setup buffer
  1299. sizeof(Setup), // setup buffer length
  1300. NULL,
  1301. 0,
  1302. pInputParamBuffer, // Input Param Buffer
  1303. InputParamBufferLength, // Input param buffer length
  1304. pOutputParamBuffer, // Output param buffer
  1305. OutputParamBufferLength, // output param buffer length
  1306. pInputDataBuffer, // Input data buffer
  1307. InputDataBufferLength, // Input data buffer length
  1308. pOutputDataBuffer, // output data buffer
  1309. OutputDataBufferLength, // output data buffer length
  1310. &ResumptionContext // the resumption context
  1311. );
  1312. if (!NT_SUCCESS(Status)) {
  1313. RxDbgTrace( 0, Dbg, ("MRxSmbDfsFsControl(%ld): Failed .. returning %lx\n",FsControlCode,Status));
  1314. } else {
  1315. RxContext->InformationToReturn = ResumptionContext.DataBytesReceived;
  1316. }
  1317. }
  1318. RxDbgTrace(-1, Dbg, ("MRxSmbDfsFsControl exit...st=%08lx\n", Status));
  1319. return Status;
  1320. }
  1321. NTSTATUS
  1322. MRxSmbFsControl(PRX_CONTEXT RxContext)
  1323. /*++
  1324. Routine Description:
  1325. This routine handles all the FSCTL's
  1326. Arguments:
  1327. RxContext - the RDBSS context
  1328. Return Value:
  1329. RXSTATUS - The return status for the operation
  1330. Notes:
  1331. Remoting of FSCTL's is permitted only to NT servers.
  1332. --*/
  1333. {
  1334. NTSTATUS Status = STATUS_SUCCESS;
  1335. RxCaptureFcb;
  1336. RxCaptureFobx;
  1337. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  1338. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1339. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1340. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1341. PFILE_OBJECT pTargetFileObject = NULL;
  1342. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1343. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  1344. REQ_NT_IO_CONTROL FsCtlSetup;
  1345. PBYTE pInputParamBuffer = NULL;
  1346. PBYTE pOutputParamBuffer = NULL;
  1347. PBYTE pInputDataBuffer = NULL;
  1348. PBYTE pOutputDataBuffer = NULL;
  1349. #ifdef _WIN64
  1350. PBYTE pThunkedInputData = NULL;
  1351. ULONG ThunkedInputDataLength = 0;
  1352. #endif
  1353. ULONG InputParamBufferLength = 0;
  1354. ULONG OutputParamBufferLength = 0;
  1355. ULONG InputDataBufferLength = 0;
  1356. ULONG OutputDataBufferLength = 0;
  1357. USHORT FileOrTreeId;
  1358. SMB_TRANSACTION_OPTIONS TransactionOptions = DEFAULT_TRANSACTION_OPTIONS;
  1359. SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
  1360. SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
  1361. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1362. BOOL CscAgentConnection = FALSE;
  1363. PAGED_CODE();
  1364. if (NodeType(capFcb) == RDBSS_NTC_DEVICE_FCB) {
  1365. return STATUS_INVALID_DEVICE_REQUEST;
  1366. }
  1367. if ((FsControlCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) &&
  1368. (RxContext->MinorFunction != IRP_MN_TRACK_LINK)) {
  1369. return STATUS_INVALID_DEVICE_REQUEST;
  1370. }
  1371. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1372. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(SrvOpen->pVNetRoot);
  1373. if (pVNetRootContext != NULL &&
  1374. FlagOn( // agent call
  1375. pVNetRootContext->Flags,
  1376. SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE))
  1377. {
  1378. CscAgentConnection = TRUE;
  1379. }
  1380. if (capFobx != NULL &&
  1381. !CscAgentConnection &&
  1382. (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen) ||
  1383. SmbCeIsServerInDisconnectedMode(pServerEntry)) ) {
  1384. return STATUS_NOT_IMPLEMENTED;
  1385. }
  1386. RxDbgTrace(+1, Dbg, ("MRxSmbFsControl...Entry FsControlCode(%lx)\n", FsControlCode));
  1387. FsCtlSetup.IsFlags = 0;
  1388. if (capFobx != NULL) {
  1389. if (NodeType(capFobx) == RDBSS_NTC_V_NETROOT) {
  1390. PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  1391. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1392. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
  1393. // It is a root open the tree id needs to be sent to the server.
  1394. FileOrTreeId = pVNetRootContext->TreeId;
  1395. } else {
  1396. if (FsControlCode != FSCTL_LMR_GET_CONNECTION_INFO) {
  1397. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  1398. if (FlagOn(pSmbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  1399. BOOLEAN FcbAcquired = FALSE;
  1400. if (!RxIsFcbAcquiredExclusive(capFcb)) {
  1401. // This assert does not take into account the fact that other threads may
  1402. // own the resource shared, in which case we DO want to block and wait for
  1403. // the resource.
  1404. //ASSERT(!RxIsFcbAcquiredShared(capFcb));
  1405. Status = RxAcquireExclusiveFcbResourceInMRx( capFcb );
  1406. FcbAcquired = (Status == STATUS_SUCCESS);
  1407. } else {
  1408. Status = STATUS_SUCCESS;
  1409. }
  1410. if (Status == STATUS_SUCCESS) {
  1411. Status = MRxSmbDeferredCreate(RxContext);
  1412. if (FcbAcquired)
  1413. RxReleaseFcbResourceInMRx( capFcb );
  1414. }
  1415. if (Status!=STATUS_SUCCESS) {
  1416. goto FINALLY;
  1417. }
  1418. }
  1419. FileOrTreeId = pSmbSrvOpen->Fid;
  1420. } else {
  1421. FileOrTreeId = 0;
  1422. }
  1423. }
  1424. } else {
  1425. FileOrTreeId = 0;
  1426. }
  1427. SmbPutAlignedUshort(&FsCtlSetup.Fid,FileOrTreeId);
  1428. SmbPutAlignedUlong(&FsCtlSetup.FunctionCode,FsControlCode);
  1429. FsCtlSetup.IsFsctl = TRUE;
  1430. TransactionOptions.NtTransactFunction = NT_TRANSACT_IOCTL;
  1431. TransactionOptions.pTransactionName = NULL;
  1432. Status = STATUS_SUCCESS;
  1433. pInputDataBuffer = pLowIoContext->ParamsFor.FsCtl.pInputBuffer;
  1434. InputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.InputBufferLength;
  1435. pOutputDataBuffer = pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  1436. OutputDataBufferLength = pLowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  1437. switch (FsControlCode & 3) {
  1438. case METHOD_NEITHER:
  1439. {
  1440. ULONG Device;
  1441. Device = FsControlCode >> 16;
  1442. if (Device != FILE_DEVICE_FILE_SYSTEM) {
  1443. return STATUS_NOT_IMPLEMENTED;
  1444. }
  1445. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  1446. try {
  1447. if (pInputDataBuffer) {
  1448. ProbeForRead(pInputDataBuffer,InputDataBufferLength,1);
  1449. }
  1450. if (pOutputDataBuffer) {
  1451. ProbeForWrite(pOutputDataBuffer,OutputDataBufferLength,1);
  1452. }
  1453. } except (EXCEPTION_EXECUTE_HANDLER) {
  1454. return STATUS_INVALID_PARAMETER;
  1455. }
  1456. }
  1457. }
  1458. // fall thru.. for those FSContolcodes that belong to FILE_DEVICE_FILE_SYSTEM
  1459. // for which METHOD_NEITHER is specified we treat them as METHOD_BUFFERED
  1460. // Not Yet implemented
  1461. case METHOD_BUFFERED:
  1462. case METHOD_IN_DIRECT:
  1463. case METHOD_OUT_DIRECT:
  1464. break;
  1465. default:
  1466. ASSERT(!"Valid Method for Fs Control");
  1467. return STATUS_INVALID_PARAMETER;
  1468. break;
  1469. }
  1470. #ifdef _WIN64
  1471. pThunkedInputData = pInputDataBuffer;
  1472. ThunkedInputDataLength = InputDataBufferLength;
  1473. #endif
  1474. // There is one FSCTL for which certain amount of preprocessing is required
  1475. // This is because the I/O subsystem passes in the information as a file
  1476. // object. The FID for the file object needs to be determined and the
  1477. // appropriate FID passed to the server instead of the file object.
  1478. if (FsControlCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) {
  1479. PREMOTE_LINK_TRACKING_INFORMATION pRemoteLinkInformation;
  1480. PMRX_FOBX pMRxFobx;
  1481. PMRX_SRV_OPEN pSrvOpen;
  1482. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  1483. try {
  1484. pRemoteLinkInformation =
  1485. (PREMOTE_LINK_TRACKING_INFORMATION)pInputDataBuffer;
  1486. if (pRemoteLinkInformation != NULL) {
  1487. pTargetFileObject = (PFILE_OBJECT)pRemoteLinkInformation->TargetFileObject;
  1488. if (pTargetFileObject != NULL) {
  1489. // Deduce the FID and substitute it for the File Object before shipping
  1490. // the FSCTL to the server.
  1491. pMRxFobx = (PMRX_FOBX)pTargetFileObject->FsContext2;
  1492. pSrvOpen = pMRxFobx->pSrvOpen;
  1493. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(pSrvOpen);
  1494. if (pSmbSrvOpen != NULL) {
  1495. pRemoteLinkInformation->TargetFileObject =
  1496. (PVOID)(pSmbSrvOpen->Fid);
  1497. } else {
  1498. Status = STATUS_INVALID_PARAMETER;
  1499. }
  1500. }
  1501. #ifdef _WIN64
  1502. if( NT_SUCCESS(Status) )
  1503. {
  1504. ThunkedInputDataLength = InputDataBufferLength;
  1505. pThunkedInputData = Smb64ThunkRemoteLinkTrackingInfo( pInputDataBuffer, &ThunkedInputDataLength, &Status );
  1506. }
  1507. #endif
  1508. } else {
  1509. Status = STATUS_INVALID_PARAMETER;
  1510. }
  1511. } except(EXCEPTION_EXECUTE_HANDLER) {
  1512. Status=STATUS_INVALID_PARAMETER;
  1513. }
  1514. } else if (FsControlCode == FSCTL_LMR_GET_CONNECTION_INFO) {
  1515. PSMBCEDB_SERVER_ENTRY pServerEntry= SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1516. Status = STATUS_INVALID_PARAMETER;
  1517. if (pOutputDataBuffer && (OutputDataBufferLength == sizeof(LMR_CONNECTION_INFO_3))) {
  1518. if (!memcmp(pOutputDataBuffer,EA_NAME_CSCAGENT,sizeof(EA_NAME_CSCAGENT))) {
  1519. MRxSmbGetConnectInfoLevel3Fields(
  1520. (PLMR_CONNECTION_INFO_3)(pOutputDataBuffer),
  1521. pServerEntry,
  1522. TRUE);
  1523. Status = STATUS_SUCCESS;
  1524. }
  1525. }
  1526. goto FINALLY;
  1527. }
  1528. if (NT_SUCCESS(Status)) {
  1529. #ifdef _WIN64
  1530. ASSERT( !( (FsControlCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) &&
  1531. (pThunkedInputData == NULL) ) );
  1532. #endif
  1533. Status = SmbCeTransact(
  1534. RxContext,
  1535. &TransactionOptions,
  1536. &FsCtlSetup,
  1537. sizeof(FsCtlSetup),
  1538. &FsCtlSetup,
  1539. sizeof(FsCtlSetup),
  1540. pInputParamBuffer,
  1541. InputParamBufferLength,
  1542. pOutputParamBuffer,
  1543. OutputParamBufferLength,
  1544. #ifndef _WIN64
  1545. pInputDataBuffer,
  1546. InputDataBufferLength,
  1547. #else
  1548. pThunkedInputData,
  1549. ThunkedInputDataLength,
  1550. #endif
  1551. pOutputDataBuffer,
  1552. OutputDataBufferLength,
  1553. &ResumptionContext);
  1554. RxContext->InformationToReturn = ResumptionContext.DataBytesReceived;
  1555. if (NT_SUCCESS(Status)) {
  1556. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1557. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1558. // invalidate the name based file info cache since it could change the attribute
  1559. // of the file on the server, i.e. FILE_ATTRIBUTE_COMPRESSED.
  1560. MRxSmbInvalidateFileInfoCache(RxContext);
  1561. // Mark FullDir Cache, weak for bdi : Current Invalidate for correctness
  1562. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, TRUE);
  1563. // update the Fcb in case of reuse since the time stamp may have changed
  1564. ClearFlag(capFcb->FcbState,FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
  1565. if( RxContext->InformationToReturn > OutputDataBufferLength ) {
  1566. Status = STATUS_BUFFER_TOO_SMALL;
  1567. }
  1568. }
  1569. if( !NT_SUCCESS( Status ) ) {
  1570. // RxContext->InformationToReturn = 0;
  1571. RxDbgTrace(0,Dbg,("MRxSmbFsControl: Transaction Request Completion Status %lx\n",Status));
  1572. }
  1573. }
  1574. FINALLY:
  1575. if( FsControlCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION )
  1576. {
  1577. #ifdef _WIN64
  1578. Smb64ReleaseThunkData( pThunkedInputData );
  1579. #endif
  1580. if( pTargetFileObject != NULL )
  1581. {
  1582. PREMOTE_LINK_TRACKING_INFORMATION pRemoteLinkInformation;
  1583. pRemoteLinkInformation =
  1584. (PREMOTE_LINK_TRACKING_INFORMATION)pInputDataBuffer;
  1585. pRemoteLinkInformation->TargetFileObject = pTargetFileObject;
  1586. }
  1587. }
  1588. RxDbgTrace(-1, Dbg, ("MRxSmbFsControl...Exit\n"));
  1589. return Status;
  1590. }
  1591. #if DBG
  1592. NTSTATUS
  1593. MRxSmbTestForLowIoIoctl(
  1594. IN PRX_CONTEXT RxContext
  1595. )
  1596. {
  1597. NTSTATUS Status = STATUS_SUCCESS;
  1598. RxCaptureFcb;RxCaptureFobx;
  1599. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  1600. PSZ Buffer = (PSZ)(LowIoContext->ParamsFor.IoCtl.pInputBuffer);
  1601. ULONG OutputBufferLength = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
  1602. ULONG InputBufferLength = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
  1603. UNICODE_STRING u;
  1604. PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME(capFobx->pSrvOpen,capFcb);
  1605. ULONG ReturnLength;
  1606. PAGED_CODE();
  1607. ReturnLength = OutputBufferLength;
  1608. if (ReturnLength > FileName->Length) {
  1609. ReturnLength = FileName->Length;
  1610. }
  1611. RxDbgTrace(0, Dbg,
  1612. ("Here in MRxSmbTestForLowIoIoctl %s, obl = %08lx, rl=%08lx\n", Buffer, OutputBufferLength, ReturnLength));
  1613. // return an obvious string to make sure that darryl is copying the results out correctly
  1614. // need to check the lengths i.e. need outputl<=inputl; also need to check that count and buffer
  1615. // are aligned for wchar
  1616. RtlCopyMemory(Buffer,FileName->Buffer,ReturnLength);
  1617. u.Buffer = (PWCHAR)(Buffer);
  1618. u.Length = u.MaximumLength = (USHORT)ReturnLength;
  1619. RtlUpcaseUnicodeString(&u,&u,FALSE);
  1620. RxContext->InformationToReturn =
  1621. //LowIoContext->ParamsFor.IoCtl.OutputBufferLength =
  1622. ReturnLength;
  1623. return(Status);
  1624. }
  1625. #endif //if DBG
  1626. NTSTATUS
  1627. MRxSmbIoCtl(
  1628. IN OUT PRX_CONTEXT RxContext)
  1629. /*++
  1630. Routine Description:
  1631. This routine performs an IOCTL operation. Currently, no calls are remoted; in
  1632. fact, the only call accepted is for debugging.
  1633. Arguments:
  1634. RxContext - the RDBSS context
  1635. Return Value:
  1636. RXSTATUS - The return status for the operation
  1637. Notes:
  1638. --*/
  1639. {
  1640. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  1641. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1642. ULONG IoControlCode = pLowIoContext->ParamsFor.IoCtl.IoControlCode;
  1643. PAGED_CODE();
  1644. RxDbgTrace(+1, Dbg, ("MRxSmbIoCtl...\n", 0));
  1645. RxDbgTrace( 0, Dbg, ("MRxSmbIoCtl = %08lx\n", IoControlCode));
  1646. switch (IoControlCode) {
  1647. #if DBG
  1648. case IOCTL_LMMR_TESTLOWIO:
  1649. Status = MRxSmbTestForLowIoIoctl(RxContext);
  1650. break;
  1651. #endif //if DBG
  1652. default:
  1653. break;
  1654. }
  1655. RxDbgTrace(-1, Dbg, ("MRxSmbIoCtl -> %08lx\n", Status ));
  1656. return Status;
  1657. }
  1658. NTSTATUS
  1659. MRxSmbGetPrintJobId(
  1660. IN OUT PRX_CONTEXT RxContext)
  1661. /*++
  1662. Routine Description:
  1663. This routine performs an FSCTL operation (remote) on a file across the network
  1664. Arguments:
  1665. RxContext - the RDBSS context
  1666. Return Value:
  1667. RXSTATUS - The return status for the operation
  1668. Notes:
  1669. The FSCTL's handled by a mini rdr can be classified into one of two categories.
  1670. In the first category are those FSCTL's whose implementation are shared between
  1671. RDBSS and the mini rdr's and in the second category are those FSCTL's which
  1672. are totally implemented by the mini rdr's. To this a third category can be
  1673. added, i.e., those FSCTL's which should never be seen by the mini rdr's. The
  1674. third category is solely intended as a debugging aid.
  1675. The FSCTL's handled by a mini rdr can be classified based on functionality
  1676. --*/
  1677. {
  1678. NTSTATUS Status;
  1679. BOOLEAN FinalizationComplete;
  1680. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
  1681. PSMBSTUFFER_BUFFER_STATE StufferState;
  1682. RxCaptureFobx;
  1683. RxCaptureFcb;
  1684. PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp;
  1685. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1686. PAGED_CODE();
  1687. RxDbgTrace(+1, Dbg, ("MRxSmbGetPrintJobId\n", 0 ));
  1688. if (capFcb == NULL || capFobx == NULL) {
  1689. return STATUS_INVALID_PARAMETER;
  1690. }
  1691. if (NodeType(capFcb) == RDBSS_NTC_DEVICE_FCB) {
  1692. return STATUS_INVALID_DEVICE_REQUEST;
  1693. }
  1694. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1695. if (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  1696. Status = MRxSmbFsControl(RxContext);
  1697. goto FINALLY;
  1698. }
  1699. if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(QUERY_PRINT_JOB_INFO) ) {
  1700. Status = STATUS_BUFFER_TOO_SMALL;
  1701. goto FINALLY;
  1702. }
  1703. Status= SmbPseCreateOrdinaryExchange(
  1704. RxContext,
  1705. capFobx->pSrvOpen->pVNetRoot,
  1706. SMBPSE_OE_FROM_GETPRINTJOBID,
  1707. MRxSmbCoreIoCtl,
  1708. &OrdinaryExchange
  1709. );
  1710. if (Status != STATUS_SUCCESS) {
  1711. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  1712. goto FINALLY;
  1713. }
  1714. OrdinaryExchange->AssociatedStufferState.CurrentCommand = SMB_COM_NO_ANDX_COMMAND;
  1715. StufferState = &OrdinaryExchange->AssociatedStufferState;
  1716. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  1717. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  1718. FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  1719. ASSERT(FinalizationComplete);
  1720. FINALLY:
  1721. RxDbgTrace(-1, Dbg, ("MRxSmbIsValidDirectory exit with status=%08lx\n", Status ));
  1722. return(Status);
  1723. }
  1724. #define SPOOLER_DEVICE 0x53
  1725. #define GET_PRINTER_ID 0x60
  1726. typedef struct _SMB_RESP_PRINT_JOB_ID {
  1727. USHORT JobId;
  1728. UCHAR ServerName[LM20_CNLEN+1];
  1729. UCHAR QueueName[LM20_QNLEN+1];
  1730. UCHAR Padding; // Unknown what this padding is..
  1731. } SMB_RESP_PRINT_JOB_ID, *PSMB_RESP_PRINT_JOB_ID;
  1732. NTSTATUS
  1733. MRxSmbCoreIoCtl(
  1734. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1735. )
  1736. /*++
  1737. Routine Description:
  1738. This is the start routine for SMB IOCTL. This initiates the construction of the
  1739. appropriate SMB.
  1740. Arguments:
  1741. pExchange - the exchange instance
  1742. Return Value:
  1743. NTSTATUS - The return status for the operation
  1744. --*/
  1745. {
  1746. NTSTATUS Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
  1747. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  1748. RxCaptureFcb; RxCaptureFobx;
  1749. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1750. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1751. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  1752. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  1753. ULONG SmbLength;
  1754. PAGED_CODE();
  1755. RxDbgTrace(+1, Dbg, ("MRxSmbCoreIoCtl\n", 0 ));
  1756. switch (OrdinaryExchange->EntryPoint) {
  1757. case SMBPSE_OE_FROM_GETPRINTJOBID:
  1758. COVERED_CALL(
  1759. MRxSmbStartSMBCommand(
  1760. StufferState,
  1761. SetInitialSMB_ForReuse,
  1762. SMB_COM_IOCTL,
  1763. SMB_REQUEST_SIZE(IOCTL),
  1764. NO_EXTRA_DATA,
  1765. SMB_BEST_ALIGNMENT(1,0),
  1766. RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  1767. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  1768. );
  1769. MRxSmbDumpStufferState (1100,"SMB w/ GFA before stuffing",StufferState);
  1770. //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
  1771. // otherwise, we don't need to copy the name here, we can just Mdl like in writes
  1772. MRxSmbStuffSMB (StufferState,
  1773. "0wwwwwwwwwwwwwwB!",
  1774. // 0 UCHAR WordCount; // Count of parameter words = 8
  1775. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  1776. SPOOLER_DEVICE, // w _USHORT( Category);
  1777. GET_PRINTER_ID, // w _USHORT( Function ); // Device function
  1778. 0, // w _USHORT( TotalParameterCount ); // Total parameter bytes being sent
  1779. 0, // w _USHORT( TotalDataCount ); // Total data bytes being sent
  1780. 0, // w _USHORT( MaxParameterCount ); // Max parameter bytes to return
  1781. 0, // w _USHORT( MaxDataCount ); // Max data bytes to return
  1782. 0, // w _ULONG ( Timeout );
  1783. 0, // w _USHORT( Reserved );
  1784. 0, // w _USHORT( ParameterCount ); // Parameter bytes sent this buffer
  1785. 0, // w _USHORT( ParameterOffset ); // Offset (from header start) to params
  1786. 0, // w _USHORT( DataCount ); // Data bytes sent this buffer
  1787. 0, // w _USHORT( DataOffset ); // Offset (from header start) to data
  1788. 0, // w _USHORT( ByteCount ); // Count of data bytes
  1789. SMB_WCT_CHECK(14) 0 // _USHORT( ByteCount ); // Count of data bytes; min = 0
  1790. // UCHAR Buffer[1]; // Reserved buffer
  1791. );
  1792. break;
  1793. default:
  1794. Status = STATUS_NOT_IMPLEMENTED;
  1795. }
  1796. if (Status == STATUS_SUCCESS) {
  1797. MRxSmbDumpStufferState (700,"SMB w/ GFA after stuffing",StufferState);
  1798. Status = SmbPseOrdinaryExchange(
  1799. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1800. SMBPSE_OETYPE_IOCTL
  1801. );
  1802. }
  1803. FINALLY:
  1804. RxDbgTrace(-1, Dbg, ("MRxSmbSynchronousGetFileAttributes exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  1805. return(Status);
  1806. }
  1807. NTSTATUS
  1808. MRxSmbFinishCoreIoCtl(
  1809. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  1810. PRESP_IOCTL Response
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This routine copies the print job ID and server and queue name to the user buffer.
  1815. Arguments:
  1816. OrdinaryExchange - the exchange instance
  1817. Response - the response
  1818. Return Value:
  1819. RXSTATUS - The return status for the operation
  1820. --*/
  1821. {
  1822. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  1823. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  1824. PIRP Irp = RxContext->CurrentIrp;
  1825. PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp;
  1826. PAGED_CODE();
  1827. RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreIoCtl\n", 0 ));
  1828. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreIoCtl:");
  1829. switch (OrdinaryExchange->EntryPoint) {
  1830. case SMBPSE_OE_FROM_GETPRINTJOBID:
  1831. if (Response->WordCount != 8 ||
  1832. SmbGetUshort(&Response->DataCount) != sizeof(SMB_RESP_PRINT_JOB_ID)) {
  1833. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1834. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1835. } else {
  1836. OEM_STRING OemString;
  1837. UNICODE_STRING UnicodeString;
  1838. PQUERY_PRINT_JOB_INFO OutputBuffer = Irp->UserBuffer;
  1839. PSMB_RESP_PRINT_JOB_ID RespPrintJobId = (PSMB_RESP_PRINT_JOB_ID)((PUCHAR)Response+(Response->DataOffset-sizeof(SMB_HEADER)));
  1840. OutputBuffer->JobId = RespPrintJobId->JobId;
  1841. RtlInitAnsiString(&OemString, RespPrintJobId->ServerName);
  1842. UnicodeString.Buffer = OutputBuffer->ServerName;
  1843. UnicodeString.MaximumLength = sizeof(OutputBuffer->ServerName);
  1844. Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
  1845. if (Status == STATUS_SUCCESS) {
  1846. RtlInitAnsiString(&OemString, RespPrintJobId->QueueName);
  1847. UnicodeString.Buffer = OutputBuffer->QueueName;
  1848. UnicodeString.MaximumLength = sizeof(OutputBuffer->QueueName);
  1849. Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
  1850. IrpSp->Parameters.FileSystemControl.InputBufferLength = sizeof(QUERY_PRINT_JOB_INFO);
  1851. }
  1852. }
  1853. break;
  1854. default:
  1855. ASSERT(FALSE);
  1856. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1857. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1858. }
  1859. RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreIoCtl returning %08lx\n", Status ));
  1860. return Status;
  1861. }
  1862. typedef struct _SecPkgContext_TargetInformation
  1863. {
  1864. unsigned long MarshalledTargetInfoLength;
  1865. unsigned char SEC_FAR * MarshalledTargetInfo;
  1866. } SecPkgContext_TargetInformation, SEC_FAR * PSecPkgContext_TargetInformation;
  1867. NTSTATUS
  1868. MRxSmbQueryTargetInfo(
  1869. PRX_CONTEXT RxContext
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. This routine performs a query target information operation against a connection
  1874. Arguments:
  1875. RxContext - the RDBSS context
  1876. Return Value:
  1877. RXSTATUS - The return status for the operation
  1878. Notes:
  1879. RDR gets the target information based on the security context of the connection and
  1880. returns the marshalled target information on the output buffer.
  1881. --*/
  1882. {
  1883. PMRX_V_NET_ROOT pVNetRoot = NULL;
  1884. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1885. NTSTATUS Status = STATUS_SUCCESS;
  1886. SECURITY_STATUS SecStatus;
  1887. SecPkgContext_TargetInformation SecTargetInfo;
  1888. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1889. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  1890. PLMR_QUERY_TARGET_INFO LmrQueryTargetInfo = RxContext->CurrentIrp->UserBuffer;
  1891. PAGED_CODE();
  1892. RxDbgTrace(+1, Dbg, ("MRxSmbQueryTargetInfo...\n", 0));
  1893. RxDbgTrace( 0, Dbg, ("MRxSmbQueryTargetInfo = %08lx\n", FsControlCode));
  1894. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  1895. // this FSCTLS is only supported from a kernel mode component
  1896. return STATUS_INVALID_DEVICE_REQUEST;
  1897. }
  1898. if (LmrQueryTargetInfo == NULL) {
  1899. return STATUS_INVALID_PARAMETER;
  1900. }
  1901. if (RxContext->pRelevantSrvOpen == NULL) {
  1902. return STATUS_INVALID_PARAMETER;
  1903. }
  1904. pVNetRoot = (PMRX_V_NET_ROOT)RxContext->pRelevantSrvOpen->pVNetRoot;
  1905. if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
  1906. return STATUS_INVALID_PARAMETER;
  1907. }
  1908. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pVNetRoot->Context;
  1909. SecStatus = QueryContextAttributesW(
  1910. &pVNetRootContext->pSessionEntry->Session.SecurityContextHandle,
  1911. SECPKG_ATTR_TARGET_INFORMATION,
  1912. &SecTargetInfo);
  1913. Status = MapSecurityError( SecStatus );
  1914. if (Status == STATUS_SUCCESS) {
  1915. if (SecTargetInfo.MarshalledTargetInfoLength+sizeof(LMR_QUERY_TARGET_INFO) > LmrQueryTargetInfo->BufferLength) {
  1916. LmrQueryTargetInfo->BufferLength = SecTargetInfo.MarshalledTargetInfoLength + sizeof(LMR_QUERY_TARGET_INFO);
  1917. Status = STATUS_BUFFER_TOO_SMALL;
  1918. } else {
  1919. RtlCopyMemory(LmrQueryTargetInfo->TargetInfoMarshalled,
  1920. SecTargetInfo.MarshalledTargetInfo,
  1921. SecTargetInfo.MarshalledTargetInfoLength);
  1922. LmrQueryTargetInfo->BufferLength = SecTargetInfo.MarshalledTargetInfoLength;
  1923. }
  1924. {
  1925. SIZE_T MarshalledTargetInfoLength_SizeT;
  1926. MarshalledTargetInfoLength_SizeT = SecTargetInfo.MarshalledTargetInfoLength;
  1927. ZwFreeVirtualMemory(
  1928. NtCurrentProcess(),
  1929. &SecTargetInfo.MarshalledTargetInfo,
  1930. &MarshalledTargetInfoLength_SizeT,
  1931. MEM_RELEASE);
  1932. ASSERT(MarshalledTargetInfoLength_SizeT <= MAXULONG);
  1933. SecTargetInfo.MarshalledTargetInfoLength = (ULONG)MarshalledTargetInfoLength_SizeT;
  1934. }
  1935. }
  1936. return Status;
  1937. }
  1938. NTSTATUS
  1939. MRxSmbQueryRemoteServerName(
  1940. PRX_CONTEXT RxContext
  1941. )
  1942. /*++
  1943. Routine Description:
  1944. This routine performs a query remote file information operation against a srvopen
  1945. Arguments:
  1946. RxContext - the RDBSS context
  1947. Return Value:
  1948. RXSTATUS - The return status for the operation
  1949. Notes:
  1950. --*/
  1951. {
  1952. PQUERY_REMOTE_SERVER_NAME info;
  1953. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  1954. RxCaptureFcb; RxCaptureFobx;
  1955. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1956. PMRX_SMB_SRV_OPEN smbSrvOpen;
  1957. PUNICODE_STRING s;
  1958. ULONG len;
  1959. PAGED_CODE();
  1960. if (SrvOpen == NULL || capFcb->pNetRoot == NULL || capFcb->pNetRoot->pSrvCall == NULL) {
  1961. return STATUS_NOT_SUPPORTED;
  1962. }
  1963. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1964. info = (PQUERY_REMOTE_SERVER_NAME) pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  1965. if (pLowIoContext->ParamsFor.FsCtl.OutputBufferLength < sizeof(QUERY_REMOTE_SERVER_NAME)) {
  1966. return STATUS_BUFFER_TOO_SMALL;
  1967. }
  1968. // we get the srvname
  1969. len = 0;
  1970. s = capFcb->pNetRoot->pSrvCall->pSrvCallName;
  1971. if (s != NULL) {
  1972. len += s->Length;
  1973. }
  1974. s = capFcb->pNetRoot->pSrvCall->pDomainName;
  1975. if (s != NULL) {
  1976. len += s->Length;
  1977. }
  1978. info->ServerNameLength = len;
  1979. RxContext->InformationToReturn = sizeof(QUERY_REMOTE_SERVER_NAME);
  1980. if (pLowIoContext->ParamsFor.FsCtl.OutputBufferLength < sizeof(QUERY_REMOTE_SERVER_NAME) + len) {
  1981. info->ServerName[0] = L'\0';
  1982. return STATUS_BUFFER_TOO_SMALL;
  1983. }
  1984. len = 0;
  1985. s = capFcb->pNetRoot->pSrvCall->pSrvCallName;
  1986. if (s != NULL) {
  1987. RtlCopyMemory(info->ServerName, s->Buffer+1, s->Length-sizeof(WCHAR));
  1988. len += s->Length - sizeof(WCHAR);
  1989. }
  1990. s = capFcb->pNetRoot->pSrvCall->pDomainName;
  1991. if (s != NULL) {
  1992. info->ServerName[len / sizeof(WCHAR)] = L'.';
  1993. len += sizeof(WCHAR);
  1994. RtlCopyMemory(&info->ServerName[len / sizeof(WCHAR)], s->Buffer, s->Length);
  1995. len += s->Length;
  1996. }
  1997. RxContext->InformationToReturn += len;
  1998. return STATUS_SUCCESS;
  1999. }