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.

1882 lines
54 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. smbctl.c
  5. Abstract:
  6. This module implements the IoControl and FsControl SMBs.
  7. Transact2 Ioctl
  8. Nt Transaction Io Control
  9. Author:
  10. Manny Weiser (mannyw) 10-Oct-91
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "smbioctl.tmh"
  15. #pragma hdrstop
  16. NTSTATUS
  17. ProcessOs2Ioctl (
  18. IN PWORK_CONTEXT WorkContext,
  19. IN USHORT Category,
  20. IN USHORT Function,
  21. IN PVOID Parameters,
  22. IN ULONG InputParameterCount,
  23. IN PULONG OutputParameterCount,
  24. IN PVOID Data,
  25. IN ULONG InputDataCount,
  26. IN ULONG MaxOutputData,
  27. IN PULONG OutputDataCount
  28. );
  29. VOID SRVFASTCALL
  30. RestartNtIoctl (
  31. IN PWORK_CONTEXT WorkContext
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text( PAGE, SrvSmbIoctl )
  35. #pragma alloc_text( PAGE, SrvSmbIoctlSecondary )
  36. #pragma alloc_text( PAGE, RestartNtIoctl )
  37. #pragma alloc_text( PAGE, SrvSmbIoctl2 )
  38. #pragma alloc_text( PAGE, SrvSmbFsctl )
  39. #pragma alloc_text( PAGE, ProcessOs2Ioctl )
  40. #endif
  41. SMB_PROCESSOR_RETURN_TYPE
  42. SrvSmbIoctl (
  43. SMB_PROCESSOR_PARAMETERS
  44. )
  45. /*++
  46. Routine Description:
  47. Processes a primary Ioctl SMB.
  48. Arguments:
  49. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  50. of the parameters to SMB processor routines.
  51. Return Value:
  52. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  53. --*/
  54. {
  55. PREQ_IOCTL request;
  56. PRESP_IOCTL response;
  57. PSMB_HEADER header;
  58. NTSTATUS status = STATUS_SUCCESS;
  59. SMB_STATUS SmbStatus = SmbStatusInProgress;
  60. PSESSION session;
  61. PTREE_CONNECT treeConnect;
  62. PRFCB rfcb;
  63. CLONG parameterOffset;
  64. CLONG parameterCount; // For input on this buffer
  65. CLONG maxParameterCount; // For output
  66. CLONG totalParameterCount; // For input
  67. CLONG parameterSize; // Max of input and output parameter counts
  68. CLONG dataOffset;
  69. CLONG responseDataOffset;
  70. CLONG dataCount; // For input on this buffer
  71. CLONG maxDataCount; // For output
  72. CLONG totalDataCount; // For input
  73. CLONG dataSize; // Max of input and output data counts
  74. CLONG smbLength;
  75. CLONG numberOfPaddings = 0;
  76. PAGED_CODE( );
  77. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  78. WorkContext->PreviousSMB = EVENT_TYPE_SMB_IOCTL;
  79. SrvWmiStartContext(WorkContext);
  80. request = (PREQ_IOCTL)WorkContext->RequestParameters;
  81. response = (PRESP_IOCTL)WorkContext->ResponseParameters;
  82. //
  83. // Since we do I/O from the SMB buffer, verify that the request and
  84. // response buffers are one and the same.
  85. //
  86. ASSERT( (PVOID)request == (PVOID)response );
  87. header = WorkContext->RequestHeader;
  88. IF_SMB_DEBUG(TRANSACTION1) {
  89. KdPrint(( "Ioctl (primary) request\n" ));
  90. }
  91. //
  92. // !!! Verify ioctl subcommand early?
  93. //
  94. parameterOffset = SmbGetUshort( &request->ParameterOffset );
  95. parameterCount = SmbGetUshort( &request->ParameterCount );
  96. maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
  97. totalParameterCount = SmbGetUshort( &request->TotalParameterCount );
  98. dataOffset = SmbGetUshort( &request->DataOffset );
  99. dataCount = SmbGetUshort( &request->DataCount );
  100. maxDataCount = SmbGetUshort( &request->MaxDataCount );
  101. totalDataCount = SmbGetUshort( &request->TotalDataCount );
  102. smbLength = WorkContext->RequestBuffer->DataLength;
  103. dataSize = MAX( dataCount, maxDataCount );
  104. parameterSize = MAX( parameterCount, maxParameterCount );
  105. if ( parameterCount != 0 ) {
  106. responseDataOffset = parameterOffset + parameterSize;
  107. } else {
  108. //
  109. // Some ioctls requests have data offset of zero like
  110. // category 0x53, function 0x60. If this is the case,
  111. // calculate the dataoffset by hand.
  112. //
  113. if ( dataOffset != 0 ) {
  114. responseDataOffset = dataOffset;
  115. } else {
  116. responseDataOffset = (CLONG) ((PUCHAR) response->Buffer -
  117. (PUCHAR) WorkContext->ResponseHeader);
  118. numberOfPaddings = ( responseDataOffset & 0x01 );
  119. responseDataOffset = responseDataOffset + numberOfPaddings;
  120. }
  121. }
  122. //
  123. // Verify the size of the smb buffer:
  124. //
  125. // Even though we know that WordCount and ByteCount are valid, it's
  126. // still possible that the offsets and lengths of the Parameter and
  127. // Data bytes are invalid. So we check them now.
  128. //
  129. // We need room in the smb buffer for the response. Ensure that
  130. // there is enough room.
  131. //
  132. // No ioctl secondary is expected. Ensure that all data and
  133. // parameters have arrrived.
  134. //
  135. // Check that the response will fit in a single buffer.
  136. //
  137. if ( ( (parameterOffset + parameterCount) > smbLength ) ||
  138. ( (dataOffset + dataCount) > smbLength ) ||
  139. ( (responseDataOffset + dataCount) >
  140. WorkContext->ResponseBuffer->BufferLength ) ||
  141. ( dataCount != totalDataCount ) ||
  142. ( parameterCount != totalParameterCount ) ||
  143. ( (parameterOffset > dataOffset) && (dataCount != 0) ) ) {
  144. IF_DEBUG(SMB_ERRORS) {
  145. KdPrint(( "SrvSmbTransaction: Invalid parameter or data "
  146. "offset+count: pOff=%ld,pCnt=%ld;",
  147. parameterOffset, parameterCount ));
  148. KdPrint(( "dOff=%ld,dCnt=%ld;", dataOffset, dataCount ));
  149. KdPrint(( "smbLen=%ld", smbLength ));
  150. }
  151. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  152. status = STATUS_INVALID_SMB;
  153. SmbStatus = SmbStatusSendResponse;
  154. goto Cleanup;
  155. }
  156. //
  157. // If a session block has not already been assigned to the current
  158. // work context, verify the UID. If verified, the address of the
  159. // session block corresponding to this user is stored in the
  160. // WorkContext block and the session block is referenced.
  161. //
  162. // If a tree connect block has not already been assigned to the
  163. // current work context, find the tree connect corresponding to the
  164. // given TID.
  165. //
  166. status = SrvVerifyUidAndTid(
  167. WorkContext,
  168. &session,
  169. &treeConnect,
  170. ShareTypeWild
  171. );
  172. if ( !NT_SUCCESS(status) ) {
  173. IF_DEBUG(SMB_ERRORS) {
  174. KdPrint(( "SrvSmbIoctl: Invalid UID or TID\n" ));
  175. }
  176. SrvSetSmbError( WorkContext, status );
  177. SmbStatus = SmbStatusSendResponse;
  178. goto Cleanup;
  179. }
  180. if( session->IsSessionExpired )
  181. {
  182. status = SESSION_EXPIRED_STATUS_CODE;
  183. SrvSetSmbError( WorkContext, status );
  184. SmbStatus = SmbStatusSendResponse;
  185. goto Cleanup;
  186. }
  187. //
  188. // Verify the FID. If verified, the RFCB block is referenced
  189. // and its addresses is stored in the WorkContext block, and the
  190. // RFCB address is returned.
  191. //
  192. rfcb = SrvVerifyFid(
  193. WorkContext,
  194. request->Fid,
  195. TRUE,
  196. SrvRestartSmbReceived, // serialize with raw write
  197. &status
  198. );
  199. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  200. if ( !NT_SUCCESS( status ) ) {
  201. //
  202. // Invalid file ID or write behind error. Reject the request.
  203. //
  204. IF_DEBUG(ERRORS) {
  205. KdPrint((
  206. "SrvSmbIoctl: Status %X on FID: 0x%lx\n",
  207. request->Fid,
  208. status
  209. ));
  210. }
  211. SrvSetSmbError( WorkContext, status );
  212. SmbStatus = SmbStatusSendResponse;
  213. goto Cleanup;
  214. }
  215. //
  216. // The work item has been queued because a raw write is in
  217. // progress.
  218. //
  219. SmbStatus = SmbStatusInProgress;
  220. goto Cleanup;
  221. }
  222. //
  223. // Make room in the SMB buffer for return parameters by copying data
  224. //
  225. if ( dataOffset != responseDataOffset && dataCount != 0) {
  226. RtlMoveMemory(
  227. (PCHAR)header + responseDataOffset,
  228. (PCHAR)header + dataOffset,
  229. dataCount
  230. );
  231. }
  232. //
  233. // Process the ioctl. The response will overwrite the request buffer.
  234. //
  235. status = ProcessOs2Ioctl(
  236. WorkContext,
  237. request->Category,
  238. request->Function,
  239. (PCHAR)WorkContext->RequestHeader + parameterOffset,
  240. totalParameterCount,
  241. &maxParameterCount,
  242. (PCHAR)WorkContext->RequestHeader + responseDataOffset,
  243. totalDataCount,
  244. WorkContext->ResponseBuffer->BufferLength -
  245. PTR_DIFF(WorkContext->RequestHeader,
  246. WorkContext->ResponseBuffer->Buffer) -
  247. responseDataOffset,
  248. &maxDataCount
  249. );
  250. //
  251. // Format and send the response, the parameter and data bytes are
  252. // already in place.
  253. //
  254. if ( !NT_SUCCESS( status ) ) {
  255. SrvSetSmbError( WorkContext, status );
  256. SmbStatus = SmbStatusSendResponse;
  257. goto Cleanup;
  258. }
  259. response->WordCount = 8;
  260. SmbPutUshort( &response->TotalParameterCount, (USHORT)maxParameterCount );
  261. SmbPutUshort( &response->TotalDataCount, (USHORT)maxDataCount );
  262. SmbPutUshort( &response->ParameterCount, (USHORT)maxParameterCount );
  263. SmbPutUshort( &response->ParameterOffset, (USHORT)parameterOffset );
  264. SmbPutUshort( &response->ParameterDisplacement, 0);
  265. SmbPutUshort( &response->DataCount, (USHORT)maxDataCount );
  266. SmbPutUshort( &response->DataOffset, (USHORT)responseDataOffset );
  267. SmbPutUshort( &response->DataDisplacement, 0 );
  268. SmbPutUshort(
  269. &response->ByteCount,
  270. (USHORT)(maxDataCount + numberOfPaddings)
  271. );
  272. WorkContext->ResponseParameters = NEXT_LOCATION(
  273. response,
  274. RESP_IOCTL,
  275. maxDataCount + numberOfPaddings
  276. );
  277. SmbStatus = SmbStatusSendResponse;
  278. Cleanup:
  279. SrvWmiEndContext(WorkContext);
  280. return SmbStatus;
  281. } // SrvSmbIoctl
  282. SMB_PROCESSOR_RETURN_TYPE
  283. SrvSmbIoctlSecondary (
  284. SMB_PROCESSOR_PARAMETERS
  285. )
  286. /*++
  287. Routine Description:
  288. Processes a secondary Ioctl SMB.
  289. Arguments:
  290. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  291. of the parameters to SMB processor routines.
  292. Return Value:
  293. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  294. --*/
  295. {
  296. PAGED_CODE( );
  297. //
  298. // This SMB is not supported.
  299. //
  300. SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
  301. return SmbStatusSendResponse;
  302. }
  303. SMB_TRANS_STATUS
  304. SrvSmbNtIoctl (
  305. SMB_PROCESSOR_PARAMETERS
  306. )
  307. /*++
  308. Routine Description:
  309. Processes a Nt Ioctl SMB.
  310. Arguments:
  311. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  312. of the parameters to SMB processor routines.
  313. Return Value:
  314. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  315. --*/
  316. {
  317. NTSTATUS status;
  318. ULONG functionCode;
  319. USHORT fid;
  320. BOOLEAN isFsctl;
  321. PREQ_NT_IO_CONTROL request;
  322. PTRANSACTION transaction;
  323. PRFCB rfcb;
  324. PMDL mdl = NULL;
  325. transaction = WorkContext->Parameters.Transaction;
  326. request = (PREQ_NT_IO_CONTROL)transaction->InSetup;
  327. functionCode = SmbGetAlignedUlong( &request->FunctionCode );
  328. fid = SmbGetAlignedUshort( &request->Fid );
  329. isFsctl = request->IsFsctl;
  330. //
  331. // Verify the FID. If verified, the RFCB block is referenced
  332. // and its addresses is stored in the WorkContext block, and the
  333. // RFCB address is returned.
  334. //
  335. rfcb = SrvVerifyFid(
  336. WorkContext,
  337. fid,
  338. TRUE,
  339. SrvRestartExecuteTransaction, // serialize with raw write
  340. &status
  341. );
  342. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  343. if ( !NT_SUCCESS( status ) ) {
  344. //
  345. // Invalid file ID or write behind error. Reject the request.
  346. //
  347. IF_DEBUG(ERRORS) {
  348. KdPrint((
  349. "SrvSmbNtIoctl: Status %X on FID: 0x%lx\n",
  350. status,
  351. fid
  352. ));
  353. }
  354. SrvSetSmbError( WorkContext, status );
  355. return SmbTransStatusErrorWithoutData;
  356. }
  357. //
  358. // The work item has been queued because a raw write is in
  359. // progress.
  360. //
  361. return SmbTransStatusInProgress;
  362. }
  363. //
  364. // Only allow these fellows against disk files
  365. //
  366. if( rfcb->ShareType != ShareTypeDisk ) {
  367. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  368. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  369. return SmbTransStatusInProgress;
  370. }
  371. CHECK_FUNCTION_ACCESS(
  372. rfcb->GrantedAccess,
  373. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  374. 0,
  375. functionCode,
  376. &status
  377. );
  378. if ( !NT_SUCCESS( status ) ) {
  379. SrvStatistics.GrantedAccessErrors++;
  380. SrvSetSmbError( WorkContext, status );
  381. return SmbTransStatusErrorWithoutData;
  382. }
  383. //
  384. // There are some functions which we cannot allow. Weed them out here
  385. //
  386. switch( functionCode ) {
  387. case FSCTL_SET_REPARSE_POINT:
  388. //
  389. // If there's not enough data, or the structure is internally inconsistent --
  390. // fail the request
  391. //
  392. status = STATUS_SUCCESS;
  393. if( transaction->DataCount == 0 ) {
  394. status = STATUS_INVALID_BUFFER_SIZE;
  395. } else if ( transaction->DataCount < REPARSE_DATA_BUFFER_HEADER_SIZE ||
  396. ((PREPARSE_DATA_BUFFER)transaction->InData)->ReparseDataLength >
  397. transaction->DataCount - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer )
  398. ) {
  399. status = STATUS_IO_REPARSE_DATA_INVALID;
  400. }
  401. if( !NT_SUCCESS( status ) ) {
  402. SrvSetSmbError( WorkContext, status );
  403. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  404. return SmbTransStatusInProgress;
  405. }
  406. //
  407. // Only an administrator is allowed to set generalized reparse points,
  408. // otherwise it is too easy to escape the share. This seems safer
  409. // than a path check, and it also allows the administrator to point
  410. // the reparse point to wherever s/he desires.
  411. //
  412. if( !SrvIsAdmin( WorkContext->Session->UserHandle ) ) {
  413. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  414. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  415. return SmbTransStatusInProgress;
  416. }
  417. break;
  418. case FSCTL_SRV_ENUMERATE_SNAPSHOTS:
  419. {
  420. if( SrvProductTypeServer )
  421. {
  422. status = SrvSnapEnumerateSnapShots( WorkContext );
  423. if( !NT_SUCCESS(status) )
  424. {
  425. SrvSetSmbError( WorkContext, status );
  426. SrvCompleteExecuteTransaction( WorkContext, (status==STATUS_BUFFER_OVERFLOW)?SmbTransStatusErrorWithData:SmbTransStatusErrorWithoutData );
  427. }
  428. else
  429. {
  430. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusSuccess );
  431. }
  432. return SmbTransStatusInProgress;
  433. }
  434. else
  435. {
  436. status = STATUS_NOT_IMPLEMENTED;
  437. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  438. return SmbTransStatusInProgress;
  439. }
  440. }
  441. break;
  442. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  443. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  444. case FSCTL_REQUEST_BATCH_OPLOCK:
  445. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  446. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  447. case FSCTL_OPLOCK_BREAK_NOTIFY:
  448. case FSCTL_MOVE_FILE:
  449. case FSCTL_MARK_HANDLE:
  450. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  451. case FSCTL_PIPE_ASSIGN_EVENT:
  452. case FSCTL_GET_VOLUME_BITMAP:
  453. case FSCTL_GET_NTFS_FILE_RECORD:
  454. // We don't support USN journal calls because they require a volume handle
  455. case FSCTL_READ_USN_JOURNAL:
  456. case FSCTL_CREATE_USN_JOURNAL:
  457. case FSCTL_QUERY_USN_JOURNAL:
  458. case FSCTL_DELETE_USN_JOURNAL:
  459. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  460. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  461. return SmbTransStatusInProgress;
  462. }
  463. if (functionCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) {
  464. // This is a FSCTL that is used for link tracking purposes. It is
  465. // an internal FSCTL issued by the I/O subsystem. Currently this
  466. // is being handled in the context of a worker thread. We need
  467. // to ensure that this arm of the code is only executed in the
  468. // context of a blocking thread.
  469. // Also note that the incoming structure will always be the 32-bit structure, even
  470. // from 64-bit machines. All structures on the wire are 32-bit for backwards compatibility
  471. KIRQL oldIrql;
  472. PRFCB rfcbTarget = NULL;
  473. USHORT TargetFid;
  474. PVOID TargetHandle;
  475. ULONG TargetInformationLength;
  476. ULONG LinkTrackingInformationSize;
  477. if( transaction->DataCount < sizeof( REMOTE_LINK_TRACKING_INFORMATION32 ) ) {
  478. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  479. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  480. return SmbTransStatusInProgress;
  481. }
  482. TargetHandle = UlongToHandle( SmbGetUlong(
  483. (PUCHAR)transaction->InData +
  484. FIELD_OFFSET(
  485. REMOTE_LINK_TRACKING_INFORMATION32,
  486. TargetFileObject)) );
  487. TargetInformationLength = SmbGetUlong(
  488. (PUCHAR)transaction->InData +
  489. FIELD_OFFSET(
  490. REMOTE_LINK_TRACKING_INFORMATION32,
  491. TargetLinkTrackingInformationLength));
  492. LinkTrackingInformationSize = FIELD_OFFSET(
  493. FILE_TRACKING_INFORMATION32,
  494. ObjectInformation) +
  495. TargetInformationLength;
  496. //
  497. // Make sure the REMOTE_LINK_TRACKING_INFORMATION structure is reasonable
  498. //
  499. if( TargetInformationLength > transaction->DataCount ||
  500. LinkTrackingInformationSize > transaction->DataCount ) {
  501. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  502. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  503. return SmbTransStatusInProgress;
  504. }
  505. if (TargetHandle != NULL) {
  506. TargetFid = (USHORT)TargetHandle;
  507. //
  508. // Verify the FID. This code is lifted from SrvVerifyFid2.
  509. //
  510. //
  511. // Acquire the spin lock that guards the connection's file table.
  512. //
  513. ACQUIRE_SPIN_LOCK( &WorkContext->Connection->SpinLock, &oldIrql );
  514. //
  515. // See if this is the cached rfcb
  516. //
  517. if ( WorkContext->Connection->CachedFid == (ULONG)TargetFid ) {
  518. rfcbTarget = WorkContext->Connection->CachedRfcb;
  519. } else {
  520. USHORT index;
  521. USHORT sequence;
  522. PTABLE_HEADER tableHeader;
  523. //
  524. // Verify that the FID is in range, is in use, and has the correct
  525. // sequence number.
  526. index = FID_INDEX( TargetFid );
  527. sequence = FID_SEQUENCE( TargetFid );
  528. tableHeader = &WorkContext->Connection->FileTable;
  529. if ( (index < (USHORT)tableHeader->TableSize) &&
  530. (tableHeader->Table[index].Owner != NULL) &&
  531. (tableHeader->Table[index].SequenceNumber == sequence) &&
  532. (GET_BLOCK_STATE(tableHeader->Table[index].Owner) == BlockStateActive) ) {
  533. rfcbTarget = tableHeader->Table[index].Owner;
  534. //
  535. // Cache the fid.
  536. //
  537. WorkContext->Connection->CachedRfcb = rfcbTarget;
  538. WorkContext->Connection->CachedFid = (ULONG)TargetFid;
  539. }
  540. }
  541. RELEASE_SPIN_LOCK( &WorkContext->Connection->SpinLock, oldIrql );
  542. }
  543. if( rfcbTarget != NULL || TargetHandle == NULL ) {
  544. PFILE_TRACKING_INFORMATION pTrackingInformation;
  545. IO_STATUS_BLOCK ioStatusBlock;
  546. // Since the data in the InData buffer is unaligned we need to allocate
  547. // a copy of the data that is aligned and copy the information over
  548. // before passing it on in the SetInformationCall
  549. // We also resize the buffer to the native structure on 64 bit (no change occurs on 32 bit)
  550. pTrackingInformation = ALLOCATE_HEAP( LinkTrackingInformationSize + sizeof(PVOID) - sizeof(ULONG), BlockTypeMisc );
  551. if (pTrackingInformation != NULL) {
  552. if (rfcbTarget != NULL) {
  553. pTrackingInformation->DestinationFile =
  554. rfcbTarget->Lfcb->FileHandle;
  555. } else {
  556. pTrackingInformation->DestinationFile = NULL;
  557. }
  558. pTrackingInformation->ObjectInformationLength =
  559. TargetInformationLength;
  560. RtlCopyMemory(
  561. pTrackingInformation->ObjectInformation,
  562. ((PUCHAR)transaction->InData +
  563. FIELD_OFFSET(
  564. REMOTE_LINK_TRACKING_INFORMATION,
  565. TargetLinkTrackingInformationBuffer)),
  566. TargetInformationLength);
  567. status = NtSetInformationFile(
  568. rfcb->Lfcb->FileHandle,
  569. &ioStatusBlock,
  570. pTrackingInformation,
  571. LinkTrackingInformationSize,
  572. FileTrackingInformation);
  573. FREE_HEAP(pTrackingInformation);
  574. } else {
  575. status = STATUS_INSUFFICIENT_RESOURCES;
  576. }
  577. } else {
  578. status = STATUS_INVALID_PARAMETER;
  579. }
  580. if (!NT_SUCCESS(status)) {
  581. SrvSetSmbError( WorkContext, status );
  582. SrvCompleteExecuteTransaction(
  583. WorkContext,
  584. SmbTransStatusErrorWithoutData
  585. );
  586. } else {
  587. transaction->DataCount = 0;
  588. transaction->ParameterCount = 0;
  589. SrvCompleteExecuteTransaction(
  590. WorkContext,
  591. SmbTransStatusSuccess
  592. );
  593. }
  594. return SmbTransStatusInProgress;
  595. }
  596. //
  597. // Since we are doing ioctls to this file, it doesn't seem like it's
  598. // a "normal" file. We had better not cache its handle after the close.
  599. // Specifically, remote setting of the file's compression state is
  600. // not reflected to the directory entry until the file is closed. And
  601. // setting a file's compression state is done with an ioctl
  602. //
  603. rfcb->IsCacheable = FALSE;
  604. if (functionCode == FSCTL_SIS_COPYFILE) {
  605. //
  606. // This the single-instance store copy FSCTL. We need to modify
  607. // the file names, which are passed as share-relative names,
  608. // to be full NT paths.
  609. //
  610. PSI_COPYFILE copyFile;
  611. PSI_COPYFILE newCopyFile;
  612. ULONG bufferLength;
  613. PWCHAR source;
  614. ULONG sourceLength;
  615. PWCHAR dest;
  616. ULONG destLength;
  617. PSHARE share;
  618. PWCHAR prefix;
  619. ULONG prefixLength;
  620. PCHAR p;
  621. ULONG addSlashToSource;
  622. ULONG addSlashToDest;
  623. copyFile = (PSI_COPYFILE)transaction->InData;
  624. bufferLength = transaction->DataCount;
  625. if( bufferLength < sizeof( SI_COPYFILE ) ) {
  626. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  627. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  628. return SmbTransStatusInProgress;
  629. }
  630. //
  631. // Get the share-relative paths.
  632. //
  633. source = copyFile->FileNameBuffer;
  634. sourceLength = copyFile->SourceFileNameLength;
  635. dest = source + (sourceLength / sizeof(WCHAR));
  636. destLength = copyFile->DestinationFileNameLength;
  637. //
  638. // Verify that the input structure is reasonable.
  639. //
  640. if ( (sourceLength > bufferLength || sourceLength == 0 ) ||
  641. (destLength > bufferLength || destLength == 0 ) ||
  642. ((FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) + sourceLength + destLength) > bufferLength) ||
  643. (*(source + (sourceLength/sizeof(WCHAR)-1)) != 0) ||
  644. (*(dest + (destLength/sizeof(WCHAR)-1)) != 0) ) {
  645. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  646. return SmbTransStatusErrorWithoutData;
  647. }
  648. ASSERT( (FSCTL_SIS_COPYFILE & 3) == METHOD_BUFFERED );
  649. //
  650. // Get the NT path prefix for the share.
  651. //
  652. share = WorkContext->TreeConnect->Share;
  653. prefix = share->NtPathName.Buffer;
  654. prefixLength = share->NtPathName.Length;
  655. //
  656. // Make sure there is exactly one slash between the share prefix
  657. // and the paths in the request.
  658. //
  659. addSlashToSource = 0;
  660. addSlashToDest = 0;
  661. if ( IS_UNICODE_PATH_SEPARATOR(*(prefix + (prefixLength/sizeof(WCHAR)-1))) ) {
  662. if ( IS_UNICODE_PATH_SEPARATOR(*source) ) {
  663. source++;
  664. sourceLength -= sizeof(WCHAR);
  665. }
  666. if ( IS_UNICODE_PATH_SEPARATOR(*dest) ) {
  667. dest++;
  668. destLength -= sizeof(WCHAR);
  669. }
  670. } else {
  671. if ( !IS_UNICODE_PATH_SEPARATOR(*source) ) {
  672. addSlashToSource = sizeof(WCHAR);
  673. }
  674. if ( !IS_UNICODE_PATH_SEPARATOR(*dest) ) {
  675. addSlashToDest = sizeof(WCHAR);
  676. }
  677. }
  678. //
  679. // Allocate space for a new FSCTL command buffer.
  680. //
  681. bufferLength = FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) +
  682. prefixLength + addSlashToSource + sourceLength +
  683. prefixLength + addSlashToSource + destLength;
  684. newCopyFile = ALLOCATE_HEAP( bufferLength, BlockTypeBuffer );
  685. if( newCopyFile == NULL ) {
  686. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  687. return SmbTransStatusErrorWithoutData;
  688. }
  689. //
  690. // Initialize the FSCTL input buffer with the full NT path names.
  691. //
  692. newCopyFile->SourceFileNameLength = prefixLength + addSlashToSource + sourceLength;
  693. newCopyFile->DestinationFileNameLength = prefixLength + addSlashToDest + destLength;
  694. newCopyFile->Flags = copyFile->Flags;
  695. p = (PCHAR)newCopyFile->FileNameBuffer;
  696. RtlCopyMemory( p, prefix, prefixLength );
  697. p += prefixLength;
  698. if ( addSlashToSource != 0 ) {
  699. *(PWCHAR)p = UNICODE_DIR_SEPARATOR_CHAR;
  700. p += sizeof(WCHAR);
  701. }
  702. RtlCopyMemory( p, source, sourceLength );
  703. p += sourceLength;
  704. RtlCopyMemory( p, prefix, prefixLength );
  705. p += prefixLength;
  706. if ( addSlashToDest != 0 ) {
  707. *(PWCHAR)p = UNICODE_DIR_SEPARATOR_CHAR;
  708. p += sizeof(WCHAR);
  709. }
  710. RtlCopyMemory( p, dest, destLength );
  711. //
  712. // Modify the transaction to point to the new buffer and indicate
  713. // that the buffer should be freed when the transaction is done.
  714. // (Note that the original buffer was allocated as part of the
  715. // transaction block and doesn't need to be freed separately.)
  716. //
  717. transaction->InData = (PVOID)newCopyFile;
  718. transaction->OutData = (PVOID)newCopyFile;
  719. transaction->DataCount = bufferLength;
  720. transaction->OutputBufferCopied = TRUE;
  721. transaction->OutDataAllocated = TRUE;
  722. }
  723. switch( functionCode & 3 ) {
  724. case METHOD_IN_DIRECT:
  725. case METHOD_OUT_DIRECT:
  726. if( transaction->TotalDataCount ) {
  727. //
  728. // Need an mdl
  729. //
  730. status = STATUS_SUCCESS;
  731. mdl = IoAllocateMdl(
  732. transaction->InData,
  733. transaction->TotalDataCount,
  734. FALSE,
  735. FALSE,
  736. NULL
  737. );
  738. if ( mdl == NULL ) {
  739. status = STATUS_INSUFF_SERVER_RESOURCES;
  740. } else {
  741. //
  742. // Build the mdl
  743. //
  744. try {
  745. MmProbeAndLockPages(
  746. mdl,
  747. KernelMode,
  748. IoReadAccess
  749. );
  750. } except( EXCEPTION_EXECUTE_HANDLER ) {
  751. status = GetExceptionCode();
  752. IoFreeMdl( mdl );
  753. mdl = NULL;
  754. }
  755. }
  756. if( !NT_SUCCESS( status ) ) {
  757. SrvSetSmbError( WorkContext, status );
  758. return SmbTransStatusErrorWithoutData;
  759. }
  760. }
  761. break;
  762. case METHOD_NEITHER:
  763. //
  764. // We need to allocate the output buffer for this fsctl, because at
  765. // this point both the input and output buffers point to the same
  766. // region of memory. This can't be guaranteed to work for METHOD_NEITHER
  767. //
  768. if( transaction->MaxDataCount ) {
  769. //
  770. // Let's not let the allocation get out of hand!
  771. //
  772. if( transaction->MaxDataCount > SrvMaxFsctlBufferSize ) {
  773. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  774. return SmbTransStatusErrorWithoutData;
  775. }
  776. transaction->OutData = ALLOCATE_HEAP( transaction->MaxDataCount, BlockTypeBuffer );
  777. if( transaction->OutData == NULL ) {
  778. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  779. return SmbTransStatusErrorWithoutData;
  780. }
  781. RtlZeroMemory( transaction->OutData, transaction->MaxDataCount );
  782. transaction->OutputBufferCopied = TRUE;
  783. transaction->OutDataAllocated = TRUE;
  784. }
  785. break;
  786. }
  787. //
  788. // Set the Restart Routine addresses in the work context block.
  789. //
  790. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  791. WorkContext->FspRestartRoutine = RestartNtIoctl;
  792. //
  793. // Build the IRP to start the I/O control.
  794. // Pass this request to the filesystem.
  795. //
  796. SrvBuildIoControlRequest(
  797. WorkContext->Irp,
  798. rfcb->Lfcb->FileObject,
  799. WorkContext,
  800. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  801. functionCode,
  802. transaction->InData,
  803. transaction->DataCount,
  804. transaction->OutData,
  805. transaction->MaxDataCount,
  806. mdl,
  807. NULL // Completion routine
  808. );
  809. (VOID)IoCallDriver(
  810. IoGetRelatedDeviceObject(rfcb->Lfcb->FileObject ),
  811. WorkContext->Irp
  812. );
  813. //
  814. // The call was successfully started, return InProgress to the caller
  815. //
  816. return SmbTransStatusInProgress;
  817. } // SrvSmbNtIoctl
  818. VOID SRVFASTCALL
  819. RestartNtIoctl (
  820. IN PWORK_CONTEXT WorkContext
  821. )
  822. /*++
  823. Routine Description:
  824. This function handles the completion of an NT Io control SMB.
  825. Arguments:
  826. WorkContext - A pointer to a WORK_CONTEXT block.
  827. Return Value:
  828. None.
  829. --*/
  830. {
  831. NTSTATUS status;
  832. ULONG length;
  833. PTRANSACTION transaction;
  834. PAGED_CODE( );
  835. //
  836. // Free the MDL if one was allocated.
  837. //
  838. if ( WorkContext->Irp->MdlAddress != NULL ) {
  839. MmUnlockPages( WorkContext->Irp->MdlAddress );
  840. IoFreeMdl( WorkContext->Irp->MdlAddress );
  841. WorkContext->Irp->MdlAddress = NULL;
  842. }
  843. //
  844. // If the Io Control request failed, set an error status in the response
  845. // header.
  846. //
  847. status = WorkContext->Irp->IoStatus.Status;
  848. if ( NT_ERROR(status) ) {
  849. IF_DEBUG(ERRORS) {
  850. KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
  851. status ));
  852. }
  853. SrvSetSmbError( WorkContext, status );
  854. SrvCompleteExecuteTransaction(
  855. WorkContext,
  856. SmbTransStatusErrorWithoutData
  857. );
  858. } else {
  859. //
  860. // Success. Prepare to generate and send the response.
  861. //
  862. transaction = WorkContext->Parameters.Transaction;
  863. length = MIN( (ULONG)WorkContext->Irp->IoStatus.Information, transaction->MaxDataCount );
  864. if ( transaction->MaxSetupCount > 0 ) {
  865. transaction->SetupCount = 1;
  866. SmbPutUshort( transaction->OutSetup, (USHORT)length );
  867. }
  868. transaction->ParameterCount = transaction->MaxParameterCount;
  869. transaction->DataCount = length;
  870. if (!NT_SUCCESS(status) ) {
  871. IF_DEBUG(ERRORS) {
  872. KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
  873. status ));
  874. }
  875. SrvSetSmbError2( WorkContext, status, TRUE );
  876. SrvCompleteExecuteTransaction(
  877. WorkContext,
  878. SmbTransStatusErrorWithData
  879. );
  880. } else {
  881. SrvCompleteExecuteTransaction(
  882. WorkContext,
  883. SmbTransStatusSuccess);
  884. }
  885. }
  886. return;
  887. } // RestartNtIoctl
  888. SMB_TRANS_STATUS
  889. SrvSmbIoctl2 (
  890. IN OUT PWORK_CONTEXT WorkContext
  891. )
  892. /*++
  893. Routine Description:
  894. Processes the Ioctl request. This request arrives in a Transaction2 SMB.
  895. Arguments:
  896. WorkContext - Supplies the address of a Work Context Block
  897. describing the current request. See smbtypes.h for a more
  898. complete description of the valid fields.
  899. Return Value:
  900. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  901. whether data should be returned to the client. See smbtypes.h
  902. for a more complete description.
  903. --*/
  904. {
  905. NTSTATUS status = STATUS_SUCCESS;
  906. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  907. PTRANSACTION transaction;
  908. PRFCB rfcb;
  909. PAGED_CODE( );
  910. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  911. WorkContext->PreviousSMB = EVENT_TYPE_SMB_IOCTL2;
  912. SrvWmiStartContext(WorkContext);
  913. transaction = WorkContext->Parameters.Transaction;
  914. IF_SMB_DEBUG(TRANSACTION2) {
  915. KdPrint(( "Ioctl2 entered; transaction 0x%p\n",
  916. transaction ));
  917. }
  918. //request = (PREQ_IOCTL2)transaction->InSetup;
  919. //
  920. // Verify the setup count.
  921. //
  922. if ( transaction->SetupCount != 4 * sizeof( USHORT ) ) {
  923. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  924. status = STATUS_INVALID_SMB;
  925. SmbStatus = SmbTransStatusErrorWithoutData;
  926. goto Cleanup;
  927. }
  928. //
  929. // Verify the FID. If verified, the RFCB block is referenced
  930. // and its addresses is stored in the WorkContext block, and the
  931. // RFCB address is returned.
  932. //
  933. rfcb = SrvVerifyFid(
  934. WorkContext,
  935. transaction->InSetup[1],
  936. TRUE,
  937. SrvRestartExecuteTransaction, // serialize with raw write
  938. &status
  939. );
  940. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  941. if ( !NT_SUCCESS( status ) ) {
  942. //
  943. // Invalid file ID or write behind error. Reject the request.
  944. //
  945. IF_DEBUG(ERRORS) {
  946. KdPrint((
  947. "SrvSmbIoctl2: Status %X on FID: 0x%lx\n",
  948. transaction->InSetup[1],
  949. status
  950. ));
  951. }
  952. SrvSetSmbError( WorkContext, status );
  953. SmbStatus = SmbTransStatusErrorWithoutData;
  954. goto Cleanup;
  955. }
  956. //
  957. // The work item has been queued because a raw write is in
  958. // progress.
  959. //
  960. SmbStatus = SmbTransStatusInProgress;
  961. goto Cleanup;
  962. }
  963. transaction->Category = transaction->InSetup[2];
  964. transaction->Function = transaction->InSetup[3];
  965. //
  966. // Perform the Ioctl
  967. //
  968. status = ProcessOs2Ioctl(
  969. WorkContext,
  970. transaction->InSetup[2],
  971. transaction->InSetup[3],
  972. transaction->InParameters,
  973. transaction->ParameterCount,
  974. &transaction->MaxParameterCount,
  975. transaction->OutData,
  976. transaction->DataCount,
  977. transaction->MaxDataCount,
  978. &transaction->MaxDataCount
  979. );
  980. //
  981. // If an error occurred, return an appropriate response.
  982. //
  983. if ( !NT_SUCCESS(status) ) {
  984. SrvSetSmbError( WorkContext, status );
  985. SmbStatus = SmbTransStatusErrorWithoutData;
  986. goto Cleanup;
  987. }
  988. transaction->SetupCount = 0;
  989. transaction->ParameterCount = transaction->MaxParameterCount;
  990. transaction->DataCount = transaction->MaxDataCount;
  991. SmbStatus = SmbTransStatusSuccess;
  992. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbIoctl2 complete.\n" ));
  993. Cleanup:
  994. SrvWmiEndContext(WorkContext);
  995. return SmbStatus;
  996. } // SrvSmbIoctl2
  997. SMB_TRANS_STATUS
  998. SrvSmbFsctl (
  999. IN OUT PWORK_CONTEXT WorkContext
  1000. )
  1001. {
  1002. PAGED_CODE( );
  1003. //
  1004. // The OS/2 redirector never sends a remote FS control request.
  1005. // If we get one, simply reply that we cannot handle it.
  1006. //
  1007. return SrvTransactionNotImplemented( WorkContext );
  1008. } // SrvSmbFsctl
  1009. #define SERIAL_DEVICE 0x1
  1010. #define PRINTER_DEVICE 0x5
  1011. #define GENERAL_DEVICE 0xB
  1012. #define SPOOLER_DEVICE 0x53
  1013. //
  1014. // Serial device functions supported
  1015. //
  1016. #define SET_BAUD_RATE 0x41
  1017. #define SET_LINE_CONTROL 0x42
  1018. #define SET_TRANSMIT_TIMEOUT 0x44
  1019. #define SET_BREAK_OFF 0x45
  1020. #define SET_MODEM_CONTROL 0x46
  1021. #define SET_BREAK_ON 0x4B
  1022. #define STOP_TRANSMIT 0x47
  1023. #define START_TRANSMIT 0x48
  1024. #define SET_DCB_INFORMATION 0x53
  1025. #define GET_BAUD_RATE 0x61
  1026. #define GET_LINE_CONTROL 0x62
  1027. #define GET_COMM_STATUS 0x64
  1028. #define GET_LINE_STATUS 0x65
  1029. #define GET_MODEM_OUTPUT 0x66
  1030. #define GET_MODEM_INPUT 0x67
  1031. #define GET_INQUEUE_COUNT 0x68
  1032. #define GET_OUTQUEUE_COUNT 0x69
  1033. #define GET_COMM_ERROR 0x6D
  1034. #define GET_COMM_EVENT 0x72
  1035. #define GET_DCB_INFORMATION 0x73
  1036. //
  1037. // Print device function supported.
  1038. //
  1039. // *** Note: The OS/2 server supports 2 additional Ioctl functions.
  1040. // ActivateFont (0x48) and QueryActiveFont (0x69). Since these
  1041. // were designed only to support IBM proplus printer from OS/2
  1042. // and we can't correctly support these function, we don't.
  1043. //
  1044. #define GET_PRINTER_ID 0x60
  1045. #define GET_PRINTER_STATUS 0x66
  1046. #define OS2_STATUS_PRINTER_HAPPY 0x90
  1047. typedef struct _SMB_IOCTL_LINECONTROL {
  1048. UCHAR DataBits;
  1049. UCHAR Parity;
  1050. UCHAR StopBits;
  1051. UCHAR TransBreak;
  1052. } SMB_IOCTL_LINE_CONTROL, *PSMB_IOCTL_LINE_CONTROL;
  1053. typedef struct _SMB_IOCTL_BAUD_RATE {
  1054. USHORT BaudRate;
  1055. } SMB_IOCTL_BAUD_RATE, *PSMB_IOCTL_BAUD_RATE;
  1056. typedef struct _SMB_IOCTL_DEVICE_CONTROL {
  1057. USHORT WriteTimeout;
  1058. USHORT ReadTimeout;
  1059. UCHAR ControlHandShake;
  1060. UCHAR FlowReplace;
  1061. UCHAR Timeout;
  1062. UCHAR ErrorReplacementChar;
  1063. UCHAR BreakReplacementChar;
  1064. UCHAR XonChar;
  1065. UCHAR XoffChar;
  1066. } SMB_IOCTL_DEVICE_CONTROL, *PSMB_IOCTL_DEVICE_CONTROL;
  1067. typedef struct _SMB_IOCTL_COMM_ERROR {
  1068. USHORT Error;
  1069. } SMB_IOCTL_COMM_ERROR, *PSMB_IOCTL_COMM_ERROR;
  1070. typedef struct _SMB_IOCTL_PRINTER_ID {
  1071. USHORT JobId;
  1072. UCHAR Buffer[1]; // server name and share name
  1073. } SMB_IOCTL_PRINTER_ID;
  1074. typedef SMB_IOCTL_PRINTER_ID SMB_UNALIGNED *PSMB_IOCTL_PRINTER_ID;
  1075. NTSTATUS
  1076. ProcessOs2Ioctl (
  1077. IN PWORK_CONTEXT WorkContext,
  1078. IN USHORT Category,
  1079. IN USHORT Function,
  1080. IN PVOID Parameters,
  1081. IN ULONG InputParameterCount,
  1082. IN OUT PULONG OutputParameterCount,
  1083. IN PVOID Data,
  1084. IN ULONG InputDataCount,
  1085. IN ULONG MaxOutputData,
  1086. IN OUT PULONG OutputDataCount
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This function handles an OS/2 ioctl. It convert the Ioctl SMB data
  1091. into an NT ioctl call, makes the call, and format the returned data
  1092. into Ioctl SMB return data.
  1093. Arguments:
  1094. WorkContext
  1095. Category
  1096. Function
  1097. Parameters
  1098. InputParameterCount
  1099. OutputParameterCount
  1100. Data
  1101. InputDataCount
  1102. OutputDataCount
  1103. Return Value:
  1104. NTSTATUS
  1105. --*/
  1106. {
  1107. IO_STATUS_BLOCK ioStatusBlock;
  1108. NTSTATUS status;
  1109. PCHAR buffer;
  1110. PLFCB lfcb = WorkContext->Rfcb->Lfcb;
  1111. HANDLE Handle = lfcb->FileHandle;
  1112. union NT_PARAMTERS {
  1113. SERIAL_BAUD_RATE BaudRate;
  1114. SERIAL_LINE_CONTROL LineControl;
  1115. SERIAL_TIMEOUTS Timeouts;
  1116. SERIAL_QUEUE_SIZE QueueSize;
  1117. ULONG WaitMask;
  1118. ULONG PurgeMask;
  1119. UCHAR ImmediateChar;
  1120. UCHAR Reserved[3];
  1121. SERIAL_CHARS Chars;
  1122. SERIAL_HANDFLOW Handflow;
  1123. SERIAL_STATUS SerialStatus;
  1124. } ntBuffer;
  1125. union SMB_PARAMETERS {
  1126. PSMB_IOCTL_BAUD_RATE BaudRate;
  1127. PSMB_IOCTL_LINE_CONTROL LineControl;
  1128. PSMB_IOCTL_DEVICE_CONTROL DeviceControl;
  1129. PSMB_IOCTL_COMM_ERROR CommError;
  1130. PSMB_IOCTL_PRINTER_ID PrinterId;
  1131. } smbParameters, smbData;
  1132. PAGED_CODE( );
  1133. InputParameterCount, InputDataCount;
  1134. switch ( Category ) {
  1135. case SERIAL_DEVICE:
  1136. switch ( Function ) {
  1137. case GET_BAUD_RATE:
  1138. if( MaxOutputData < sizeof( SMB_IOCTL_BAUD_RATE ) ) {
  1139. status = STATUS_INVALID_SMB;
  1140. break;
  1141. }
  1142. status = NtDeviceIoControlFile(
  1143. Handle,
  1144. 0,
  1145. NULL,
  1146. NULL,
  1147. &ioStatusBlock,
  1148. IOCTL_SERIAL_GET_BAUD_RATE,
  1149. NULL,
  1150. 0,
  1151. &ntBuffer,
  1152. sizeof( SERIAL_BAUD_RATE )
  1153. );
  1154. //
  1155. // Convert the response to OS/2 format.
  1156. //
  1157. // !!! ULONG to USHORT conversion.
  1158. //
  1159. smbData.BaudRate = (PSMB_IOCTL_BAUD_RATE)Data;
  1160. if ( NT_SUCCESS( status ) ) {
  1161. smbData.BaudRate->BaudRate = (USHORT) ntBuffer.BaudRate.BaudRate;
  1162. *OutputParameterCount = 0;
  1163. *OutputDataCount = sizeof( SMB_IOCTL_BAUD_RATE );
  1164. }
  1165. break;
  1166. case SET_BAUD_RATE:
  1167. //
  1168. // Convert the request to NT format.
  1169. //
  1170. smbParameters.BaudRate =
  1171. (PSMB_IOCTL_BAUD_RATE)Parameters;
  1172. ntBuffer.BaudRate.BaudRate = smbParameters.BaudRate->BaudRate;
  1173. status = NtDeviceIoControlFile(
  1174. Handle,
  1175. 0,
  1176. NULL,
  1177. NULL,
  1178. &ioStatusBlock,
  1179. IOCTL_SERIAL_SET_BAUD_RATE,
  1180. &ntBuffer,
  1181. sizeof( SERIAL_BAUD_RATE ),
  1182. NULL,
  1183. 0
  1184. );
  1185. *OutputParameterCount = 0;
  1186. *OutputDataCount = 0;
  1187. break;
  1188. case SET_LINE_CONTROL:
  1189. //
  1190. // Convert the request to NT format.
  1191. //
  1192. smbParameters.LineControl =
  1193. (PSMB_IOCTL_LINE_CONTROL)Parameters;
  1194. ntBuffer.LineControl.StopBits = smbParameters.LineControl->StopBits;
  1195. ntBuffer.LineControl.Parity = smbParameters.LineControl->Parity;
  1196. ntBuffer.LineControl.WordLength = smbParameters.LineControl->DataBits;
  1197. // !!! What about TransmitBreak?
  1198. status = NtDeviceIoControlFile(
  1199. Handle,
  1200. 0,
  1201. NULL,
  1202. NULL,
  1203. &ioStatusBlock,
  1204. IOCTL_SERIAL_SET_LINE_CONTROL,
  1205. &ntBuffer,
  1206. sizeof( SERIAL_LINE_CONTROL ),
  1207. NULL,
  1208. 0
  1209. );
  1210. *OutputParameterCount = 0;
  1211. *OutputDataCount = 0;
  1212. break;
  1213. case GET_LINE_CONTROL:
  1214. if( MaxOutputData < sizeof( SMB_IOCTL_LINE_CONTROL ) ) {
  1215. status = STATUS_INVALID_SMB;
  1216. break;
  1217. }
  1218. smbData.LineControl = (PSMB_IOCTL_LINE_CONTROL)Data;
  1219. status = NtDeviceIoControlFile(
  1220. Handle,
  1221. 0,
  1222. NULL,
  1223. NULL,
  1224. &ioStatusBlock,
  1225. IOCTL_SERIAL_GET_LINE_CONTROL,
  1226. NULL,
  1227. 0,
  1228. &ntBuffer,
  1229. sizeof( SERIAL_LINE_CONTROL )
  1230. );
  1231. //
  1232. // Convert the response to OS/2 format.
  1233. //
  1234. if ( NT_SUCCESS( status ) ) {
  1235. smbData.LineControl->DataBits = ntBuffer.LineControl.WordLength;
  1236. smbData.LineControl->Parity = ntBuffer.LineControl.Parity;
  1237. smbData.LineControl->StopBits = ntBuffer.LineControl.StopBits;
  1238. smbData.LineControl->TransBreak = 0; // !!!
  1239. *OutputParameterCount = 0;
  1240. *OutputDataCount = sizeof( SMB_IOCTL_LINE_CONTROL );
  1241. }
  1242. break;
  1243. case GET_DCB_INFORMATION:
  1244. if( MaxOutputData < sizeof( SMB_IOCTL_DEVICE_CONTROL ) ) {
  1245. status = STATUS_INVALID_SMB;
  1246. break;
  1247. }
  1248. smbData.DeviceControl =
  1249. (PSMB_IOCTL_DEVICE_CONTROL)Data;
  1250. status = NtDeviceIoControlFile(
  1251. Handle,
  1252. 0,
  1253. NULL,
  1254. NULL,
  1255. &ioStatusBlock,
  1256. IOCTL_SERIAL_GET_TIMEOUTS,
  1257. NULL,
  1258. 0,
  1259. &ntBuffer,
  1260. sizeof( SERIAL_TIMEOUTS )
  1261. );
  1262. //
  1263. // Convert the response to OS/2 format.
  1264. //
  1265. // !!! Verify units are correct
  1266. if ( NT_SUCCESS( status ) ) {
  1267. smbData.DeviceControl->WriteTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout; // !!!
  1268. smbData.DeviceControl->ReadTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout;
  1269. } else {
  1270. break;
  1271. }
  1272. status = NtDeviceIoControlFile(
  1273. Handle,
  1274. 0,
  1275. NULL,
  1276. NULL,
  1277. &ioStatusBlock,
  1278. IOCTL_SERIAL_GET_TIMEOUTS,
  1279. NULL,
  1280. 0,
  1281. &ntBuffer,
  1282. sizeof( SERIAL_TIMEOUTS )
  1283. );
  1284. //
  1285. // Convert the response to OS/2 format.
  1286. //
  1287. if ( NT_SUCCESS( status ) ) {
  1288. smbData.DeviceControl->XonChar = ntBuffer.Chars.XonChar;
  1289. smbData.DeviceControl->XoffChar = ntBuffer.Chars.XoffChar;
  1290. smbData.DeviceControl->ErrorReplacementChar = ntBuffer.Chars.ErrorChar;
  1291. smbData.DeviceControl->BreakReplacementChar = ntBuffer.Chars.BreakChar;
  1292. } else {
  1293. break;
  1294. }
  1295. smbData.DeviceControl->ControlHandShake = 0; // !!!
  1296. smbData.DeviceControl->FlowReplace = 0; // !!!
  1297. smbData.DeviceControl->Timeout = 0; // !!!
  1298. *OutputParameterCount = 0;
  1299. *OutputDataCount = sizeof( SMB_IOCTL_DEVICE_CONTROL );
  1300. break;
  1301. case SET_DCB_INFORMATION:
  1302. //
  1303. // Lie. Pretend this succeeded.
  1304. //
  1305. status = STATUS_SUCCESS;
  1306. *OutputParameterCount = 0;
  1307. *OutputDataCount = 0;
  1308. break;
  1309. case GET_COMM_ERROR:
  1310. //
  1311. // Pretend that there is no comm error.
  1312. //
  1313. smbData.CommError = (PSMB_IOCTL_COMM_ERROR)Data;
  1314. status = STATUS_SUCCESS;
  1315. if ( NT_SUCCESS( status ) ) {
  1316. smbData.CommError->Error = 0;
  1317. *OutputParameterCount = 0;
  1318. *OutputDataCount = sizeof( SMB_IOCTL_COMM_ERROR );
  1319. }
  1320. break;
  1321. case SET_TRANSMIT_TIMEOUT:
  1322. case SET_BREAK_OFF:
  1323. case SET_MODEM_CONTROL:
  1324. case SET_BREAK_ON:
  1325. case STOP_TRANSMIT:
  1326. case START_TRANSMIT:
  1327. case GET_COMM_STATUS:
  1328. case GET_LINE_STATUS:
  1329. case GET_MODEM_OUTPUT:
  1330. case GET_MODEM_INPUT:
  1331. case GET_INQUEUE_COUNT:
  1332. case GET_OUTQUEUE_COUNT:
  1333. case GET_COMM_EVENT:
  1334. status = STATUS_NOT_IMPLEMENTED;
  1335. break;
  1336. default:
  1337. status = STATUS_INVALID_PARAMETER;
  1338. }
  1339. break;
  1340. case PRINTER_DEVICE:
  1341. IF_SMB_DEBUG( TRANSACTION2 ) {
  1342. KdPrint(( "ProcessOs2Ioctl: print IOCTL function %lx received.\n",
  1343. Function ));
  1344. }
  1345. switch ( Function ) {
  1346. case GET_PRINTER_STATUS:
  1347. *OutputParameterCount = 0;
  1348. *OutputDataCount = 0;
  1349. if ( *(PCHAR)Parameters != 0 ) {
  1350. status = STATUS_INVALID_PARAMETER;
  1351. } else {
  1352. //
  1353. // Always return STATUS_PRINTER_HAPPY
  1354. //
  1355. if( MaxOutputData < sizeof( CHAR ) ) {
  1356. status = STATUS_INVALID_SMB;
  1357. } else {
  1358. *(PCHAR)Data = (CHAR)OS2_STATUS_PRINTER_HAPPY;
  1359. *OutputParameterCount = 0;
  1360. *OutputDataCount = sizeof( CHAR );
  1361. status = STATUS_SUCCESS;
  1362. }
  1363. break;
  1364. }
  1365. default:
  1366. *OutputParameterCount = 0;
  1367. *OutputDataCount = 0;
  1368. status = STATUS_NOT_SUPPORTED;
  1369. }
  1370. status = STATUS_SUCCESS;
  1371. *OutputParameterCount = 0;
  1372. *OutputDataCount = 0;
  1373. break;
  1374. case SPOOLER_DEVICE:
  1375. IF_SMB_DEBUG( TRANSACTION2 ) {
  1376. KdPrint(( "ProcessOs2Ioctl: spool IOCTL function %lx received.\n",
  1377. Function ));
  1378. }
  1379. switch ( Function ) {
  1380. case GET_PRINTER_ID:
  1381. {
  1382. PUNICODE_STRING shareName = &WorkContext->TreeConnect->Share->ShareName;
  1383. OEM_STRING ansiShare;
  1384. if( MaxOutputData < 2 * (LM20_CNLEN + 1) ) {
  1385. status = STATUS_INVALID_SMB;
  1386. break;
  1387. }
  1388. smbData.PrinterId = (PSMB_IOCTL_PRINTER_ID) Data;
  1389. smbData.PrinterId->JobId = (USHORT)lfcb->JobId;
  1390. buffer = (PCHAR)smbData.PrinterId->Buffer;
  1391. if ( WorkContext->Connection->Endpoint->TransportAddress.Buffer != NULL ) {
  1392. RtlCopyMemory(
  1393. buffer,
  1394. WorkContext->Connection->Endpoint->TransportAddress.Buffer,
  1395. MIN(WorkContext->Connection->Endpoint->TransportAddress.Length+1,LM20_CNLEN)
  1396. );
  1397. } else {
  1398. *buffer = '\0';
  1399. }
  1400. buffer += LM20_CNLEN;
  1401. *buffer++ = '\0';
  1402. status = RtlUnicodeStringToOemString(
  1403. &ansiShare,
  1404. shareName,
  1405. TRUE
  1406. );
  1407. if ( NT_SUCCESS(status) ) {
  1408. if ( ansiShare.Length >= LM20_NNLEN ) {
  1409. RtlCopyMemory(
  1410. buffer,
  1411. ansiShare.Buffer,
  1412. LM20_NNLEN
  1413. );
  1414. } else {
  1415. RtlCopyMemory(
  1416. buffer,
  1417. ansiShare.Buffer,
  1418. ansiShare.Length + 1
  1419. );
  1420. }
  1421. RtlFreeAnsiString(&ansiShare);
  1422. } else {
  1423. *buffer = '\0';
  1424. }
  1425. status = STATUS_SUCCESS;
  1426. buffer += LM20_NNLEN;
  1427. *buffer++ = '\0';
  1428. *OutputParameterCount = 0;
  1429. //
  1430. // data length is equal to the job id +
  1431. // the computer name + the share name + 1
  1432. // I don't know what the last + 1 is for but OS/2
  1433. // sends it.
  1434. //
  1435. *OutputDataCount = sizeof(USHORT) + LM20_CNLEN + 1 +
  1436. LM20_NNLEN + 2;
  1437. }
  1438. break;
  1439. default:
  1440. *OutputParameterCount = 0;
  1441. *OutputDataCount = 0;
  1442. status = STATUS_NOT_SUPPORTED;
  1443. }
  1444. break;
  1445. case GENERAL_DEVICE:
  1446. status = STATUS_NOT_IMPLEMENTED;
  1447. break;
  1448. default:
  1449. // for OS/2 1.x compatibility
  1450. status = STATUS_SUCCESS;
  1451. *OutputParameterCount = 0;
  1452. *OutputDataCount = 0;
  1453. }
  1454. IF_SMB_DEBUG( TRANSACTION2 ) {
  1455. KdPrint( (
  1456. "Category %x, Function %x returns %lx\n",
  1457. Category,
  1458. Function,
  1459. status
  1460. ));
  1461. }
  1462. return status;
  1463. } // ProcessOs2Ioctl