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.

1987 lines
60 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. if( transaction->SetupCount * sizeof(USHORT) < sizeof(REQ_NT_IO_CONTROL ) )
  327. {
  328. IF_DEBUG(ERRORS) {
  329. KdPrint(("SrvSmbNtIoctl: Not enough Setup bytes sent\n"));
  330. }
  331. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  332. return SmbTransStatusErrorWithoutData;
  333. }
  334. request = (PREQ_NT_IO_CONTROL)transaction->InSetup;
  335. functionCode = SmbGetAlignedUlong( &request->FunctionCode );
  336. fid = SmbGetAlignedUshort( &request->Fid );
  337. isFsctl = request->IsFsctl;
  338. //
  339. // Verify the FID. If verified, the RFCB block is referenced
  340. // and its addresses is stored in the WorkContext block, and the
  341. // RFCB address is returned.
  342. //
  343. rfcb = SrvVerifyFid(
  344. WorkContext,
  345. fid,
  346. TRUE,
  347. SrvRestartExecuteTransaction, // serialize with raw write
  348. &status
  349. );
  350. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  351. if ( !NT_SUCCESS( status ) ) {
  352. //
  353. // Invalid file ID or write behind error. Reject the request.
  354. //
  355. IF_DEBUG(ERRORS) {
  356. KdPrint((
  357. "SrvSmbNtIoctl: Status %X on FID: 0x%lx\n",
  358. status,
  359. fid
  360. ));
  361. }
  362. SrvSetSmbError( WorkContext, status );
  363. return SmbTransStatusErrorWithoutData;
  364. }
  365. //
  366. // The work item has been queued because a raw write is in
  367. // progress.
  368. //
  369. return SmbTransStatusInProgress;
  370. }
  371. //
  372. // Only allow these fellows against disk files
  373. //
  374. if( rfcb->ShareType != ShareTypeDisk ) {
  375. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  376. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  377. return SmbTransStatusInProgress;
  378. }
  379. CHECK_FUNCTION_ACCESS(
  380. rfcb->GrantedAccess,
  381. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  382. 0,
  383. functionCode,
  384. &status
  385. );
  386. if ( !NT_SUCCESS( status ) ) {
  387. SrvStatistics.GrantedAccessErrors++;
  388. SrvSetSmbError( WorkContext, status );
  389. return SmbTransStatusErrorWithoutData;
  390. }
  391. //
  392. // There are some functions which we cannot allow. Weed them out here
  393. //
  394. switch( functionCode ) {
  395. case FSCTL_SET_REPARSE_POINT:
  396. //
  397. // If there's not enough data, or the structure is internally inconsistent --
  398. // fail the request
  399. //
  400. status = STATUS_SUCCESS;
  401. if( transaction->DataCount == 0 ) {
  402. status = STATUS_INVALID_BUFFER_SIZE;
  403. } else if ( transaction->DataCount < REPARSE_DATA_BUFFER_HEADER_SIZE ||
  404. ((PREPARSE_DATA_BUFFER)transaction->InData)->ReparseDataLength >
  405. transaction->DataCount - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer )
  406. ) {
  407. status = STATUS_IO_REPARSE_DATA_INVALID;
  408. }
  409. if( !NT_SUCCESS( status ) ) {
  410. SrvSetSmbError( WorkContext, status );
  411. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  412. return SmbTransStatusInProgress;
  413. }
  414. //
  415. // Only an administrator is allowed to set generalized reparse points,
  416. // otherwise it is too easy to escape the share. This seems safer
  417. // than a path check, and it also allows the administrator to point
  418. // the reparse point to wherever s/he desires.
  419. //
  420. if( !WorkContext->Session->IsAdmin ) {
  421. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  422. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  423. return SmbTransStatusInProgress;
  424. }
  425. break;
  426. case FSCTL_SRV_ENUMERATE_SNAPSHOTS:
  427. {
  428. if( SrvProductTypeServer )
  429. {
  430. status = SrvSnapEnumerateSnapShots( WorkContext );
  431. if( !NT_SUCCESS(status) )
  432. {
  433. SrvSetSmbError( WorkContext, status );
  434. SrvCompleteExecuteTransaction( WorkContext, (status==STATUS_BUFFER_OVERFLOW)?SmbTransStatusErrorWithData:SmbTransStatusErrorWithoutData );
  435. }
  436. else
  437. {
  438. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusSuccess );
  439. }
  440. return SmbTransStatusInProgress;
  441. }
  442. else
  443. {
  444. status = STATUS_NOT_IMPLEMENTED;
  445. SrvSetSmbError( WorkContext, status );
  446. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  447. return SmbTransStatusInProgress;
  448. }
  449. }
  450. break;
  451. case FSCTL_SRV_REQUEST_RESUME_KEY:
  452. {
  453. // Queries the Resume Key for a given file
  454. ULONG resumeKey = rfcb->GlobalRfcbListEntry.ResumeHandle;
  455. if( transaction->MaxDataCount < sizeof(SRV_REQUEST_RESUME_KEY) )
  456. {
  457. status = STATUS_INVALID_PARAMETER;
  458. SrvSetSmbError( WorkContext, status );
  459. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  460. }
  461. else
  462. {
  463. PSRV_REQUEST_RESUME_KEY pResumeData = (PSRV_REQUEST_RESUME_KEY)transaction->OutData;
  464. ULONG InLength = transaction->DataCount;
  465. transaction->DataCount = sizeof(SRV_REQUEST_RESUME_KEY);
  466. pResumeData->Key.ResumeKey = (UINT64)(rfcb->GlobalRfcbListEntry.ResumeHandle);
  467. pResumeData->Key.Timestamp = (UINT64)(rfcb->PagedRfcb->OpenTime.QuadPart);
  468. pResumeData->Key.Pid = (UINT64)SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  469. pResumeData->Key.Pid |= ((UINT64)SmbGetAlignedUshort( &WorkContext->RequestHeader->PidHigh ) << 16);
  470. ACQUIRE_LOCK( &SrvConfigurationLock );
  471. if( SrvLWIOContext )
  472. {
  473. if( transaction->MaxDataCount < FIELD_OFFSET(SRV_REQUEST_RESUME_KEY, Context) + SrvLWIOContextLength )
  474. {
  475. pResumeData->ContextLength = SrvLWIOContextLength;
  476. status = STATUS_BUFFER_TOO_SMALL;
  477. }
  478. else
  479. {
  480. RtlCopyMemory( pResumeData->Context, SrvLWIOContext, SrvLWIOContextLength );
  481. pResumeData->ContextLength = SrvLWIOContextLength;
  482. if( SrvLWIOCallback )
  483. {
  484. status = SrvLWIOCallback( WorkContext->Connection->OemClientMachineName,
  485. WorkContext->SecurityContext->UserHandle,
  486. pResumeData, transaction->MaxDataCount,
  487. transaction->InData, InLength);
  488. }
  489. else
  490. {
  491. status = STATUS_SUCCESS;
  492. }
  493. transaction->DataCount = FIELD_OFFSET(SRV_REQUEST_RESUME_KEY, Context) + pResumeData->ContextLength;
  494. }
  495. }
  496. else
  497. {
  498. pResumeData->ContextLength = 0;
  499. status = STATUS_SUCCESS;
  500. }
  501. RELEASE_LOCK( &SrvConfigurationLock );
  502. if( !NT_SUCCESS(status) )
  503. {
  504. SrvSetSmbError( WorkContext, status );
  505. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  506. }
  507. else
  508. {
  509. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusSuccess );
  510. }
  511. }
  512. return SmbTransStatusInProgress;
  513. }
  514. break;
  515. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  516. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  517. case FSCTL_REQUEST_BATCH_OPLOCK:
  518. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  519. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  520. case FSCTL_OPLOCK_BREAK_NOTIFY:
  521. case FSCTL_MOVE_FILE:
  522. case FSCTL_MARK_HANDLE:
  523. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  524. case FSCTL_PIPE_ASSIGN_EVENT:
  525. case FSCTL_GET_VOLUME_BITMAP:
  526. case FSCTL_GET_NTFS_FILE_RECORD:
  527. case FSCTL_INVALIDATE_VOLUMES:
  528. // We don't support USN journal calls because they require a volume handle
  529. case FSCTL_READ_USN_JOURNAL:
  530. case FSCTL_CREATE_USN_JOURNAL:
  531. case FSCTL_QUERY_USN_JOURNAL:
  532. case FSCTL_DELETE_USN_JOURNAL:
  533. case FSCTL_ENUM_USN_DATA:
  534. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  535. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  536. return SmbTransStatusInProgress;
  537. }
  538. if (functionCode == FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) {
  539. // This is a FSCTL that is used for link tracking purposes. It is
  540. // an internal FSCTL issued by the I/O subsystem. Currently this
  541. // is being handled in the context of a worker thread. We need
  542. // to ensure that this arm of the code is only executed in the
  543. // context of a blocking thread.
  544. // Also note that the incoming structure will always be the 32-bit structure, even
  545. // from 64-bit machines. All structures on the wire are 32-bit for backwards compatibility
  546. KIRQL oldIrql;
  547. PRFCB rfcbTarget = NULL;
  548. USHORT TargetFid;
  549. PVOID TargetHandle;
  550. ULONG TargetInformationLength;
  551. ULONG LinkTrackingInformationSize;
  552. if( transaction->DataCount < sizeof( REMOTE_LINK_TRACKING_INFORMATION32 ) ) {
  553. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  554. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  555. return SmbTransStatusInProgress;
  556. }
  557. TargetHandle = UlongToHandle( SmbGetUlong(
  558. (PUCHAR)transaction->InData +
  559. FIELD_OFFSET(
  560. REMOTE_LINK_TRACKING_INFORMATION32,
  561. TargetFileObject)) );
  562. TargetInformationLength = SmbGetUlong(
  563. (PUCHAR)transaction->InData +
  564. FIELD_OFFSET(
  565. REMOTE_LINK_TRACKING_INFORMATION32,
  566. TargetLinkTrackingInformationLength));
  567. LinkTrackingInformationSize = FIELD_OFFSET(
  568. FILE_TRACKING_INFORMATION32,
  569. ObjectInformation) +
  570. TargetInformationLength;
  571. //
  572. // Make sure the REMOTE_LINK_TRACKING_INFORMATION structure is reasonable
  573. //
  574. if( TargetInformationLength > transaction->DataCount ||
  575. LinkTrackingInformationSize > transaction->DataCount ) {
  576. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  577. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  578. return SmbTransStatusInProgress;
  579. }
  580. if (TargetHandle != NULL) {
  581. TargetFid = (USHORT)TargetHandle;
  582. //
  583. // Verify the FID. This code is lifted from SrvVerifyFid2.
  584. //
  585. //
  586. // Acquire the spin lock that guards the connection's file table.
  587. //
  588. ACQUIRE_SPIN_LOCK( &WorkContext->Connection->SpinLock, &oldIrql );
  589. //
  590. // See if this is the cached rfcb
  591. //
  592. if ( WorkContext->Connection->CachedFid == (ULONG)TargetFid ) {
  593. rfcbTarget = WorkContext->Connection->CachedRfcb;
  594. } else {
  595. USHORT index;
  596. USHORT sequence;
  597. PTABLE_HEADER tableHeader;
  598. //
  599. // Verify that the FID is in range, is in use, and has the correct
  600. // sequence number.
  601. index = FID_INDEX( TargetFid );
  602. sequence = FID_SEQUENCE( TargetFid );
  603. tableHeader = &WorkContext->Connection->FileTable;
  604. if ( (index < (USHORT)tableHeader->TableSize) &&
  605. (tableHeader->Table[index].Owner != NULL) &&
  606. (tableHeader->Table[index].SequenceNumber == sequence) &&
  607. (GET_BLOCK_STATE(tableHeader->Table[index].Owner) == BlockStateActive) ) {
  608. rfcbTarget = tableHeader->Table[index].Owner;
  609. //
  610. // Cache the fid.
  611. //
  612. WorkContext->Connection->CachedRfcb = rfcbTarget;
  613. WorkContext->Connection->CachedFid = (ULONG)TargetFid;
  614. }
  615. }
  616. RELEASE_SPIN_LOCK( &WorkContext->Connection->SpinLock, oldIrql );
  617. }
  618. if( rfcbTarget != NULL || TargetHandle == NULL ) {
  619. PFILE_TRACKING_INFORMATION pTrackingInformation;
  620. IO_STATUS_BLOCK ioStatusBlock;
  621. // Since the data in the InData buffer is unaligned we need to allocate
  622. // a copy of the data that is aligned and copy the information over
  623. // before passing it on in the SetInformationCall
  624. // We also resize the buffer to the native structure on 64 bit (no change occurs on 32 bit)
  625. pTrackingInformation = ALLOCATE_HEAP( LinkTrackingInformationSize + sizeof(PVOID) - sizeof(ULONG), BlockTypeMisc );
  626. if (pTrackingInformation != NULL) {
  627. if (rfcbTarget != NULL) {
  628. pTrackingInformation->DestinationFile =
  629. rfcbTarget->Lfcb->FileHandle;
  630. } else {
  631. pTrackingInformation->DestinationFile = NULL;
  632. }
  633. pTrackingInformation->ObjectInformationLength =
  634. TargetInformationLength;
  635. RtlCopyMemory(
  636. pTrackingInformation->ObjectInformation,
  637. ((PUCHAR)transaction->InData +
  638. FIELD_OFFSET(
  639. REMOTE_LINK_TRACKING_INFORMATION,
  640. TargetLinkTrackingInformationBuffer)),
  641. TargetInformationLength);
  642. status = NtSetInformationFile(
  643. rfcb->Lfcb->FileHandle,
  644. &ioStatusBlock,
  645. pTrackingInformation,
  646. LinkTrackingInformationSize,
  647. FileTrackingInformation);
  648. FREE_HEAP(pTrackingInformation);
  649. } else {
  650. status = STATUS_INSUFFICIENT_RESOURCES;
  651. }
  652. } else {
  653. status = STATUS_INVALID_PARAMETER;
  654. }
  655. if (!NT_SUCCESS(status)) {
  656. SrvSetSmbError( WorkContext, status );
  657. SrvCompleteExecuteTransaction(
  658. WorkContext,
  659. SmbTransStatusErrorWithoutData
  660. );
  661. } else {
  662. transaction->DataCount = 0;
  663. transaction->ParameterCount = 0;
  664. SrvCompleteExecuteTransaction(
  665. WorkContext,
  666. SmbTransStatusSuccess
  667. );
  668. }
  669. return SmbTransStatusInProgress;
  670. }
  671. //
  672. // Since we are doing ioctls to this file, it doesn't seem like it's
  673. // a "normal" file. We had better not cache its handle after the close.
  674. // Specifically, remote setting of the file's compression state is
  675. // not reflected to the directory entry until the file is closed. And
  676. // setting a file's compression state is done with an ioctl
  677. //
  678. rfcb->IsCacheable = FALSE;
  679. if (functionCode == FSCTL_SIS_COPYFILE) {
  680. //
  681. // This the single-instance store copy FSCTL. We need to modify
  682. // the file names, which are passed as share-relative names,
  683. // to be full NT paths.
  684. //
  685. PSI_COPYFILE copyFile;
  686. PSI_COPYFILE newCopyFile;
  687. ULONG bufferLength;
  688. PWCHAR source;
  689. ULONG sourceLength;
  690. PWCHAR dest;
  691. ULONG destLength;
  692. PSHARE share;
  693. PWCHAR prefix;
  694. ULONG prefixLength;
  695. PCHAR p;
  696. ULONG addSlashToSource;
  697. ULONG addSlashToDest;
  698. copyFile = (PSI_COPYFILE)transaction->InData;
  699. bufferLength = transaction->DataCount;
  700. if( bufferLength < sizeof( SI_COPYFILE ) ) {
  701. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  702. SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData );
  703. return SmbTransStatusInProgress;
  704. }
  705. //
  706. // Get the share-relative paths.
  707. //
  708. source = copyFile->FileNameBuffer;
  709. sourceLength = copyFile->SourceFileNameLength;
  710. dest = source + (sourceLength / sizeof(WCHAR));
  711. destLength = copyFile->DestinationFileNameLength;
  712. //
  713. // Verify that the input structure is reasonable.
  714. //
  715. if ( (sourceLength > bufferLength || sourceLength == 0 ) ||
  716. (destLength > bufferLength || destLength == 0 ) ||
  717. ((FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) + sourceLength + destLength) > bufferLength) ||
  718. (*(source + (sourceLength/sizeof(WCHAR)-1)) != 0) ||
  719. (*(dest + (destLength/sizeof(WCHAR)-1)) != 0) ) {
  720. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  721. return SmbTransStatusErrorWithoutData;
  722. }
  723. ASSERT( (FSCTL_SIS_COPYFILE & 3) == METHOD_BUFFERED );
  724. //
  725. // Get the NT path prefix for the share.
  726. //
  727. share = WorkContext->TreeConnect->Share;
  728. prefix = share->NtPathName.Buffer;
  729. prefixLength = share->NtPathName.Length;
  730. //
  731. // Make sure there is exactly one slash between the share prefix
  732. // and the paths in the request.
  733. //
  734. addSlashToSource = 0;
  735. addSlashToDest = 0;
  736. if ( IS_UNICODE_PATH_SEPARATOR(*(prefix + (prefixLength/sizeof(WCHAR)-1))) ) {
  737. if ( IS_UNICODE_PATH_SEPARATOR(*source) ) {
  738. source++;
  739. sourceLength -= sizeof(WCHAR);
  740. }
  741. if ( IS_UNICODE_PATH_SEPARATOR(*dest) ) {
  742. dest++;
  743. destLength -= sizeof(WCHAR);
  744. }
  745. } else {
  746. if ( !IS_UNICODE_PATH_SEPARATOR(*source) ) {
  747. addSlashToSource = sizeof(WCHAR);
  748. }
  749. if ( !IS_UNICODE_PATH_SEPARATOR(*dest) ) {
  750. addSlashToDest = sizeof(WCHAR);
  751. }
  752. }
  753. //
  754. // Allocate space for a new FSCTL command buffer.
  755. //
  756. bufferLength = FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) +
  757. prefixLength + addSlashToSource + sourceLength +
  758. prefixLength + addSlashToSource + destLength;
  759. newCopyFile = ALLOCATE_HEAP( bufferLength, BlockTypeBuffer );
  760. if( newCopyFile == NULL ) {
  761. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  762. return SmbTransStatusErrorWithoutData;
  763. }
  764. //
  765. // Initialize the FSCTL input buffer with the full NT path names.
  766. //
  767. newCopyFile->SourceFileNameLength = prefixLength + addSlashToSource + sourceLength;
  768. newCopyFile->DestinationFileNameLength = prefixLength + addSlashToDest + destLength;
  769. newCopyFile->Flags = copyFile->Flags;
  770. p = (PCHAR)newCopyFile->FileNameBuffer;
  771. RtlCopyMemory( p, prefix, prefixLength );
  772. p += prefixLength;
  773. if ( addSlashToSource != 0 ) {
  774. *(PWCHAR)p = UNICODE_DIR_SEPARATOR_CHAR;
  775. p += sizeof(WCHAR);
  776. }
  777. RtlCopyMemory( p, source, sourceLength );
  778. p += sourceLength;
  779. RtlCopyMemory( p, prefix, prefixLength );
  780. p += prefixLength;
  781. if ( addSlashToDest != 0 ) {
  782. *(PWCHAR)p = UNICODE_DIR_SEPARATOR_CHAR;
  783. p += sizeof(WCHAR);
  784. }
  785. RtlCopyMemory( p, dest, destLength );
  786. //
  787. // Modify the transaction to point to the new buffer and indicate
  788. // that the buffer should be freed when the transaction is done.
  789. // (Note that the original buffer was allocated as part of the
  790. // transaction block and doesn't need to be freed separately.)
  791. //
  792. transaction->InData = (PVOID)newCopyFile;
  793. transaction->OutData = (PVOID)newCopyFile;
  794. transaction->DataCount = bufferLength;
  795. transaction->OutputBufferCopied = TRUE;
  796. transaction->OutDataAllocated = TRUE;
  797. }
  798. switch( functionCode & 3 ) {
  799. case METHOD_IN_DIRECT:
  800. case METHOD_OUT_DIRECT:
  801. if( transaction->TotalDataCount ) {
  802. //
  803. // Need an mdl
  804. //
  805. status = STATUS_SUCCESS;
  806. mdl = IoAllocateMdl(
  807. transaction->InData,
  808. transaction->TotalDataCount,
  809. FALSE,
  810. FALSE,
  811. NULL
  812. );
  813. if ( mdl == NULL ) {
  814. status = STATUS_INSUFF_SERVER_RESOURCES;
  815. } else {
  816. //
  817. // Build the mdl
  818. //
  819. try {
  820. MmProbeAndLockPages(
  821. mdl,
  822. KernelMode,
  823. IoReadAccess
  824. );
  825. } except( EXCEPTION_EXECUTE_HANDLER ) {
  826. status = GetExceptionCode();
  827. IoFreeMdl( mdl );
  828. mdl = NULL;
  829. }
  830. }
  831. if( !NT_SUCCESS( status ) ) {
  832. SrvSetSmbError( WorkContext, status );
  833. return SmbTransStatusErrorWithoutData;
  834. }
  835. }
  836. break;
  837. case METHOD_NEITHER:
  838. //
  839. // We need to allocate the output buffer for this fsctl, because at
  840. // this point both the input and output buffers point to the same
  841. // region of memory. This can't be guaranteed to work for METHOD_NEITHER
  842. //
  843. if( transaction->MaxDataCount ) {
  844. //
  845. // Let's not let the allocation get out of hand!
  846. //
  847. if( transaction->MaxDataCount > SrvMaxFsctlBufferSize ) {
  848. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  849. return SmbTransStatusErrorWithoutData;
  850. }
  851. transaction->OutData = ALLOCATE_HEAP( transaction->MaxDataCount, BlockTypeBuffer );
  852. if( transaction->OutData == NULL ) {
  853. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  854. return SmbTransStatusErrorWithoutData;
  855. }
  856. RtlZeroMemory( transaction->OutData, transaction->MaxDataCount );
  857. transaction->OutputBufferCopied = TRUE;
  858. transaction->OutDataAllocated = TRUE;
  859. }
  860. break;
  861. }
  862. //
  863. // Set the Restart Routine addresses in the work context block.
  864. //
  865. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  866. WorkContext->FspRestartRoutine = RestartNtIoctl;
  867. //
  868. // Build the IRP to start the I/O control.
  869. // Pass this request to the filesystem.
  870. //
  871. SrvBuildIoControlRequest(
  872. WorkContext->Irp,
  873. rfcb->Lfcb->FileObject,
  874. WorkContext,
  875. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  876. functionCode,
  877. transaction->InData,
  878. transaction->DataCount,
  879. transaction->OutData,
  880. transaction->MaxDataCount,
  881. mdl,
  882. NULL // Completion routine
  883. );
  884. (VOID)IoCallDriver(
  885. IoGetRelatedDeviceObject(rfcb->Lfcb->FileObject ),
  886. WorkContext->Irp
  887. );
  888. //
  889. // The call was successfully started, return InProgress to the caller
  890. //
  891. return SmbTransStatusInProgress;
  892. } // SrvSmbNtIoctl
  893. VOID SRVFASTCALL
  894. RestartNtIoctl (
  895. IN PWORK_CONTEXT WorkContext
  896. )
  897. /*++
  898. Routine Description:
  899. This function handles the completion of an NT Io control SMB.
  900. Arguments:
  901. WorkContext - A pointer to a WORK_CONTEXT block.
  902. Return Value:
  903. None.
  904. --*/
  905. {
  906. NTSTATUS status;
  907. ULONG length;
  908. PTRANSACTION transaction;
  909. PAGED_CODE( );
  910. //
  911. // Free the MDL if one was allocated.
  912. //
  913. if ( WorkContext->Irp->MdlAddress != NULL ) {
  914. MmUnlockPages( WorkContext->Irp->MdlAddress );
  915. IoFreeMdl( WorkContext->Irp->MdlAddress );
  916. WorkContext->Irp->MdlAddress = NULL;
  917. }
  918. //
  919. // If the Io Control request failed, set an error status in the response
  920. // header.
  921. //
  922. status = WorkContext->Irp->IoStatus.Status;
  923. if ( NT_ERROR(status) ) {
  924. IF_DEBUG(ERRORS) {
  925. KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
  926. status ));
  927. }
  928. SrvSetSmbError( WorkContext, status );
  929. SrvCompleteExecuteTransaction(
  930. WorkContext,
  931. SmbTransStatusErrorWithoutData
  932. );
  933. } else {
  934. //
  935. // Success. Prepare to generate and send the response.
  936. //
  937. transaction = WorkContext->Parameters.Transaction;
  938. length = MIN( (ULONG)WorkContext->Irp->IoStatus.Information, transaction->MaxDataCount );
  939. if ( transaction->MaxSetupCount > 0 ) {
  940. transaction->SetupCount = 1;
  941. SmbPutUshort( transaction->OutSetup, (USHORT)length );
  942. }
  943. transaction->ParameterCount = transaction->MaxParameterCount;
  944. transaction->DataCount = length;
  945. if (!NT_SUCCESS(status) ) {
  946. IF_DEBUG(ERRORS) {
  947. KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
  948. status ));
  949. }
  950. SrvSetSmbError2( WorkContext, status, TRUE );
  951. SrvCompleteExecuteTransaction(
  952. WorkContext,
  953. SmbTransStatusErrorWithData
  954. );
  955. } else {
  956. SrvCompleteExecuteTransaction(
  957. WorkContext,
  958. SmbTransStatusSuccess);
  959. }
  960. }
  961. return;
  962. } // RestartNtIoctl
  963. SMB_TRANS_STATUS
  964. SrvSmbIoctl2 (
  965. IN OUT PWORK_CONTEXT WorkContext
  966. )
  967. /*++
  968. Routine Description:
  969. Processes the Ioctl request. This request arrives in a Transaction2 SMB.
  970. Arguments:
  971. WorkContext - Supplies the address of a Work Context Block
  972. describing the current request. See smbtypes.h for a more
  973. complete description of the valid fields.
  974. Return Value:
  975. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  976. whether data should be returned to the client. See smbtypes.h
  977. for a more complete description.
  978. --*/
  979. {
  980. NTSTATUS status = STATUS_SUCCESS;
  981. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  982. PTRANSACTION transaction;
  983. PRFCB rfcb;
  984. PAGED_CODE( );
  985. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  986. WorkContext->PreviousSMB = EVENT_TYPE_SMB_IOCTL2;
  987. SrvWmiStartContext(WorkContext);
  988. transaction = WorkContext->Parameters.Transaction;
  989. IF_SMB_DEBUG(TRANSACTION2) {
  990. KdPrint(( "Ioctl2 entered; transaction 0x%p\n",
  991. transaction ));
  992. }
  993. //request = (PREQ_IOCTL2)transaction->InSetup;
  994. //
  995. // Verify the setup count.
  996. //
  997. if ( transaction->SetupCount != 4 * sizeof( USHORT ) ) {
  998. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  999. status = STATUS_INVALID_SMB;
  1000. SmbStatus = SmbTransStatusErrorWithoutData;
  1001. goto Cleanup;
  1002. }
  1003. //
  1004. // Verify the FID. If verified, the RFCB block is referenced
  1005. // and its addresses is stored in the WorkContext block, and the
  1006. // RFCB address is returned.
  1007. //
  1008. rfcb = SrvVerifyFid(
  1009. WorkContext,
  1010. transaction->InSetup[1],
  1011. TRUE,
  1012. SrvRestartExecuteTransaction, // serialize with raw write
  1013. &status
  1014. );
  1015. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1016. if ( !NT_SUCCESS( status ) ) {
  1017. //
  1018. // Invalid file ID or write behind error. Reject the request.
  1019. //
  1020. IF_DEBUG(ERRORS) {
  1021. KdPrint((
  1022. "SrvSmbIoctl2: Status %X on FID: 0x%lx\n",
  1023. transaction->InSetup[1],
  1024. status
  1025. ));
  1026. }
  1027. SrvSetSmbError( WorkContext, status );
  1028. SmbStatus = SmbTransStatusErrorWithoutData;
  1029. goto Cleanup;
  1030. }
  1031. //
  1032. // The work item has been queued because a raw write is in
  1033. // progress.
  1034. //
  1035. SmbStatus = SmbTransStatusInProgress;
  1036. goto Cleanup;
  1037. }
  1038. transaction->Category = transaction->InSetup[2];
  1039. transaction->Function = transaction->InSetup[3];
  1040. //
  1041. // Perform the Ioctl
  1042. //
  1043. status = ProcessOs2Ioctl(
  1044. WorkContext,
  1045. transaction->InSetup[2],
  1046. transaction->InSetup[3],
  1047. transaction->InParameters,
  1048. transaction->ParameterCount,
  1049. &transaction->MaxParameterCount,
  1050. transaction->OutData,
  1051. transaction->DataCount,
  1052. transaction->MaxDataCount,
  1053. &transaction->MaxDataCount
  1054. );
  1055. //
  1056. // If an error occurred, return an appropriate response.
  1057. //
  1058. if ( !NT_SUCCESS(status) ) {
  1059. SrvSetSmbError( WorkContext, status );
  1060. SmbStatus = SmbTransStatusErrorWithoutData;
  1061. goto Cleanup;
  1062. }
  1063. transaction->SetupCount = 0;
  1064. transaction->ParameterCount = transaction->MaxParameterCount;
  1065. transaction->DataCount = transaction->MaxDataCount;
  1066. SmbStatus = SmbTransStatusSuccess;
  1067. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbIoctl2 complete.\n" ));
  1068. Cleanup:
  1069. SrvWmiEndContext(WorkContext);
  1070. return SmbStatus;
  1071. } // SrvSmbIoctl2
  1072. SMB_TRANS_STATUS
  1073. SrvSmbFsctl (
  1074. IN OUT PWORK_CONTEXT WorkContext
  1075. )
  1076. {
  1077. PAGED_CODE( );
  1078. //
  1079. // The OS/2 redirector never sends a remote FS control request.
  1080. // If we get one, simply reply that we cannot handle it.
  1081. //
  1082. return SrvTransactionNotImplemented( WorkContext );
  1083. } // SrvSmbFsctl
  1084. #define SERIAL_DEVICE 0x1
  1085. #define PRINTER_DEVICE 0x5
  1086. #define GENERAL_DEVICE 0xB
  1087. #define SPOOLER_DEVICE 0x53
  1088. //
  1089. // Serial device functions supported
  1090. //
  1091. #define SET_BAUD_RATE 0x41
  1092. #define SET_LINE_CONTROL 0x42
  1093. #define SET_TRANSMIT_TIMEOUT 0x44
  1094. #define SET_BREAK_OFF 0x45
  1095. #define SET_MODEM_CONTROL 0x46
  1096. #define SET_BREAK_ON 0x4B
  1097. #define STOP_TRANSMIT 0x47
  1098. #define START_TRANSMIT 0x48
  1099. #define SET_DCB_INFORMATION 0x53
  1100. #define GET_BAUD_RATE 0x61
  1101. #define GET_LINE_CONTROL 0x62
  1102. #define GET_COMM_STATUS 0x64
  1103. #define GET_LINE_STATUS 0x65
  1104. #define GET_MODEM_OUTPUT 0x66
  1105. #define GET_MODEM_INPUT 0x67
  1106. #define GET_INQUEUE_COUNT 0x68
  1107. #define GET_OUTQUEUE_COUNT 0x69
  1108. #define GET_COMM_ERROR 0x6D
  1109. #define GET_COMM_EVENT 0x72
  1110. #define GET_DCB_INFORMATION 0x73
  1111. //
  1112. // Print device function supported.
  1113. //
  1114. // *** Note: The OS/2 server supports 2 additional Ioctl functions.
  1115. // ActivateFont (0x48) and QueryActiveFont (0x69). Since these
  1116. // were designed only to support IBM proplus printer from OS/2
  1117. // and we can't correctly support these function, we don't.
  1118. //
  1119. #define GET_PRINTER_ID 0x60
  1120. #define GET_PRINTER_STATUS 0x66
  1121. #define OS2_STATUS_PRINTER_HAPPY 0x90
  1122. typedef struct _SMB_IOCTL_LINECONTROL {
  1123. UCHAR DataBits;
  1124. UCHAR Parity;
  1125. UCHAR StopBits;
  1126. UCHAR TransBreak;
  1127. } SMB_IOCTL_LINE_CONTROL, *PSMB_IOCTL_LINE_CONTROL;
  1128. typedef struct _SMB_IOCTL_BAUD_RATE {
  1129. USHORT BaudRate;
  1130. } SMB_IOCTL_BAUD_RATE, *PSMB_IOCTL_BAUD_RATE;
  1131. typedef struct _SMB_IOCTL_DEVICE_CONTROL {
  1132. USHORT WriteTimeout;
  1133. USHORT ReadTimeout;
  1134. UCHAR ControlHandShake;
  1135. UCHAR FlowReplace;
  1136. UCHAR Timeout;
  1137. UCHAR ErrorReplacementChar;
  1138. UCHAR BreakReplacementChar;
  1139. UCHAR XonChar;
  1140. UCHAR XoffChar;
  1141. } SMB_IOCTL_DEVICE_CONTROL, *PSMB_IOCTL_DEVICE_CONTROL;
  1142. typedef struct _SMB_IOCTL_COMM_ERROR {
  1143. USHORT Error;
  1144. } SMB_IOCTL_COMM_ERROR, *PSMB_IOCTL_COMM_ERROR;
  1145. typedef struct _SMB_IOCTL_PRINTER_ID {
  1146. USHORT JobId;
  1147. UCHAR Buffer[1]; // server name and share name
  1148. } SMB_IOCTL_PRINTER_ID;
  1149. typedef SMB_IOCTL_PRINTER_ID SMB_UNALIGNED *PSMB_IOCTL_PRINTER_ID;
  1150. NTSTATUS
  1151. ProcessOs2Ioctl (
  1152. IN PWORK_CONTEXT WorkContext,
  1153. IN USHORT Category,
  1154. IN USHORT Function,
  1155. IN PVOID Parameters,
  1156. IN ULONG InputParameterCount,
  1157. IN OUT PULONG OutputParameterCount,
  1158. IN PVOID Data,
  1159. IN ULONG InputDataCount,
  1160. IN ULONG MaxOutputData,
  1161. IN OUT PULONG OutputDataCount
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. This function handles an OS/2 ioctl. It convert the Ioctl SMB data
  1166. into an NT ioctl call, makes the call, and format the returned data
  1167. into Ioctl SMB return data.
  1168. Arguments:
  1169. WorkContext
  1170. Category
  1171. Function
  1172. Parameters
  1173. InputParameterCount
  1174. OutputParameterCount
  1175. Data
  1176. InputDataCount
  1177. OutputDataCount
  1178. Return Value:
  1179. NTSTATUS
  1180. --*/
  1181. {
  1182. IO_STATUS_BLOCK ioStatusBlock;
  1183. NTSTATUS status;
  1184. PCHAR buffer;
  1185. PLFCB lfcb = WorkContext->Rfcb->Lfcb;
  1186. HANDLE Handle = lfcb->FileHandle;
  1187. union NT_PARAMTERS {
  1188. SERIAL_BAUD_RATE BaudRate;
  1189. SERIAL_LINE_CONTROL LineControl;
  1190. SERIAL_TIMEOUTS Timeouts;
  1191. SERIAL_QUEUE_SIZE QueueSize;
  1192. ULONG WaitMask;
  1193. ULONG PurgeMask;
  1194. UCHAR ImmediateChar;
  1195. UCHAR Reserved[3];
  1196. SERIAL_CHARS Chars;
  1197. SERIAL_HANDFLOW Handflow;
  1198. SERIAL_STATUS SerialStatus;
  1199. } ntBuffer;
  1200. union SMB_PARAMETERS {
  1201. PSMB_IOCTL_BAUD_RATE BaudRate;
  1202. PSMB_IOCTL_LINE_CONTROL LineControl;
  1203. PSMB_IOCTL_DEVICE_CONTROL DeviceControl;
  1204. PSMB_IOCTL_COMM_ERROR CommError;
  1205. PSMB_IOCTL_PRINTER_ID PrinterId;
  1206. } smbParameters, smbData;
  1207. PAGED_CODE( );
  1208. InputParameterCount, InputDataCount;
  1209. switch ( Category ) {
  1210. case SERIAL_DEVICE:
  1211. switch ( Function ) {
  1212. case GET_BAUD_RATE:
  1213. if( MaxOutputData < sizeof( SMB_IOCTL_BAUD_RATE ) ) {
  1214. status = STATUS_INVALID_SMB;
  1215. break;
  1216. }
  1217. status = NtDeviceIoControlFile(
  1218. Handle,
  1219. 0,
  1220. NULL,
  1221. NULL,
  1222. &ioStatusBlock,
  1223. IOCTL_SERIAL_GET_BAUD_RATE,
  1224. NULL,
  1225. 0,
  1226. &ntBuffer,
  1227. sizeof( SERIAL_BAUD_RATE )
  1228. );
  1229. //
  1230. // Convert the response to OS/2 format.
  1231. //
  1232. // !!! ULONG to USHORT conversion.
  1233. //
  1234. smbData.BaudRate = (PSMB_IOCTL_BAUD_RATE)Data;
  1235. if ( NT_SUCCESS( status ) ) {
  1236. smbData.BaudRate->BaudRate = (USHORT) ntBuffer.BaudRate.BaudRate;
  1237. *OutputParameterCount = 0;
  1238. *OutputDataCount = sizeof( SMB_IOCTL_BAUD_RATE );
  1239. }
  1240. break;
  1241. case SET_BAUD_RATE:
  1242. if( InputParameterCount < sizeof(SMB_IOCTL_BAUD_RATE) )
  1243. {
  1244. status = STATUS_INVALID_SMB;
  1245. break;
  1246. }
  1247. //
  1248. // Convert the request to NT format.
  1249. //
  1250. smbParameters.BaudRate =
  1251. (PSMB_IOCTL_BAUD_RATE)Parameters;
  1252. ntBuffer.BaudRate.BaudRate = smbParameters.BaudRate->BaudRate;
  1253. status = NtDeviceIoControlFile(
  1254. Handle,
  1255. 0,
  1256. NULL,
  1257. NULL,
  1258. &ioStatusBlock,
  1259. IOCTL_SERIAL_SET_BAUD_RATE,
  1260. &ntBuffer,
  1261. sizeof( SERIAL_BAUD_RATE ),
  1262. NULL,
  1263. 0
  1264. );
  1265. *OutputParameterCount = 0;
  1266. *OutputDataCount = 0;
  1267. break;
  1268. case SET_LINE_CONTROL:
  1269. if( InputParameterCount < sizeof(SMB_IOCTL_LINE_CONTROL) )
  1270. {
  1271. status = STATUS_INVALID_SMB;
  1272. break;
  1273. }
  1274. //
  1275. // Convert the request to NT format.
  1276. //
  1277. smbParameters.LineControl =
  1278. (PSMB_IOCTL_LINE_CONTROL)Parameters;
  1279. ntBuffer.LineControl.StopBits = smbParameters.LineControl->StopBits;
  1280. ntBuffer.LineControl.Parity = smbParameters.LineControl->Parity;
  1281. ntBuffer.LineControl.WordLength = smbParameters.LineControl->DataBits;
  1282. // !!! What about TransmitBreak?
  1283. status = NtDeviceIoControlFile(
  1284. Handle,
  1285. 0,
  1286. NULL,
  1287. NULL,
  1288. &ioStatusBlock,
  1289. IOCTL_SERIAL_SET_LINE_CONTROL,
  1290. &ntBuffer,
  1291. sizeof( SERIAL_LINE_CONTROL ),
  1292. NULL,
  1293. 0
  1294. );
  1295. *OutputParameterCount = 0;
  1296. *OutputDataCount = 0;
  1297. break;
  1298. case GET_LINE_CONTROL:
  1299. if( MaxOutputData < sizeof( SMB_IOCTL_LINE_CONTROL ) ) {
  1300. status = STATUS_INVALID_SMB;
  1301. break;
  1302. }
  1303. smbData.LineControl = (PSMB_IOCTL_LINE_CONTROL)Data;
  1304. status = NtDeviceIoControlFile(
  1305. Handle,
  1306. 0,
  1307. NULL,
  1308. NULL,
  1309. &ioStatusBlock,
  1310. IOCTL_SERIAL_GET_LINE_CONTROL,
  1311. NULL,
  1312. 0,
  1313. &ntBuffer,
  1314. sizeof( SERIAL_LINE_CONTROL )
  1315. );
  1316. //
  1317. // Convert the response to OS/2 format.
  1318. //
  1319. if ( NT_SUCCESS( status ) ) {
  1320. smbData.LineControl->DataBits = ntBuffer.LineControl.WordLength;
  1321. smbData.LineControl->Parity = ntBuffer.LineControl.Parity;
  1322. smbData.LineControl->StopBits = ntBuffer.LineControl.StopBits;
  1323. smbData.LineControl->TransBreak = 0; // !!!
  1324. *OutputParameterCount = 0;
  1325. *OutputDataCount = sizeof( SMB_IOCTL_LINE_CONTROL );
  1326. }
  1327. break;
  1328. case GET_DCB_INFORMATION:
  1329. if( MaxOutputData < sizeof( SMB_IOCTL_DEVICE_CONTROL ) ) {
  1330. status = STATUS_INVALID_SMB;
  1331. break;
  1332. }
  1333. smbData.DeviceControl =
  1334. (PSMB_IOCTL_DEVICE_CONTROL)Data;
  1335. status = NtDeviceIoControlFile(
  1336. Handle,
  1337. 0,
  1338. NULL,
  1339. NULL,
  1340. &ioStatusBlock,
  1341. IOCTL_SERIAL_GET_TIMEOUTS,
  1342. NULL,
  1343. 0,
  1344. &ntBuffer,
  1345. sizeof( SERIAL_TIMEOUTS )
  1346. );
  1347. //
  1348. // Convert the response to OS/2 format.
  1349. //
  1350. // !!! Verify units are correct
  1351. if ( NT_SUCCESS( status ) ) {
  1352. smbData.DeviceControl->WriteTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout; // !!!
  1353. smbData.DeviceControl->ReadTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout;
  1354. } else {
  1355. break;
  1356. }
  1357. status = NtDeviceIoControlFile(
  1358. Handle,
  1359. 0,
  1360. NULL,
  1361. NULL,
  1362. &ioStatusBlock,
  1363. IOCTL_SERIAL_GET_TIMEOUTS,
  1364. NULL,
  1365. 0,
  1366. &ntBuffer,
  1367. sizeof( SERIAL_TIMEOUTS )
  1368. );
  1369. //
  1370. // Convert the response to OS/2 format.
  1371. //
  1372. if ( NT_SUCCESS( status ) ) {
  1373. smbData.DeviceControl->XonChar = ntBuffer.Chars.XonChar;
  1374. smbData.DeviceControl->XoffChar = ntBuffer.Chars.XoffChar;
  1375. smbData.DeviceControl->ErrorReplacementChar = ntBuffer.Chars.ErrorChar;
  1376. smbData.DeviceControl->BreakReplacementChar = ntBuffer.Chars.BreakChar;
  1377. } else {
  1378. break;
  1379. }
  1380. smbData.DeviceControl->ControlHandShake = 0; // !!!
  1381. smbData.DeviceControl->FlowReplace = 0; // !!!
  1382. smbData.DeviceControl->Timeout = 0; // !!!
  1383. *OutputParameterCount = 0;
  1384. *OutputDataCount = sizeof( SMB_IOCTL_DEVICE_CONTROL );
  1385. break;
  1386. case SET_DCB_INFORMATION:
  1387. //
  1388. // Lie. Pretend this succeeded.
  1389. //
  1390. status = STATUS_SUCCESS;
  1391. *OutputParameterCount = 0;
  1392. *OutputDataCount = 0;
  1393. break;
  1394. case GET_COMM_ERROR:
  1395. //
  1396. // Pretend that there is no comm error.
  1397. //
  1398. if( MaxOutputData < sizeof(SMB_IOCTL_COMM_ERROR) )
  1399. {
  1400. status = STATUS_INVALID_SMB;
  1401. break;
  1402. }
  1403. smbData.CommError = (PSMB_IOCTL_COMM_ERROR)Data;
  1404. status = STATUS_SUCCESS;
  1405. if ( NT_SUCCESS( status ) ) {
  1406. smbData.CommError->Error = 0;
  1407. *OutputParameterCount = 0;
  1408. *OutputDataCount = sizeof( SMB_IOCTL_COMM_ERROR );
  1409. }
  1410. break;
  1411. case SET_TRANSMIT_TIMEOUT:
  1412. case SET_BREAK_OFF:
  1413. case SET_MODEM_CONTROL:
  1414. case SET_BREAK_ON:
  1415. case STOP_TRANSMIT:
  1416. case START_TRANSMIT:
  1417. case GET_COMM_STATUS:
  1418. case GET_LINE_STATUS:
  1419. case GET_MODEM_OUTPUT:
  1420. case GET_MODEM_INPUT:
  1421. case GET_INQUEUE_COUNT:
  1422. case GET_OUTQUEUE_COUNT:
  1423. case GET_COMM_EVENT:
  1424. status = STATUS_NOT_IMPLEMENTED;
  1425. break;
  1426. default:
  1427. status = STATUS_INVALID_PARAMETER;
  1428. }
  1429. break;
  1430. case PRINTER_DEVICE:
  1431. IF_SMB_DEBUG( TRANSACTION2 ) {
  1432. KdPrint(( "ProcessOs2Ioctl: print IOCTL function %lx received.\n",
  1433. Function ));
  1434. }
  1435. switch ( Function ) {
  1436. case GET_PRINTER_STATUS:
  1437. *OutputParameterCount = 0;
  1438. *OutputDataCount = 0;
  1439. if ( InputParameterCount < sizeof(CHAR) ||
  1440. *(PCHAR)Parameters != 0 ) {
  1441. status = STATUS_INVALID_PARAMETER;
  1442. } else {
  1443. //
  1444. // Always return STATUS_PRINTER_HAPPY
  1445. //
  1446. if( MaxOutputData < sizeof( CHAR ) ) {
  1447. status = STATUS_INVALID_SMB;
  1448. } else {
  1449. *(PCHAR)Data = (CHAR)OS2_STATUS_PRINTER_HAPPY;
  1450. *OutputParameterCount = 0;
  1451. *OutputDataCount = sizeof( CHAR );
  1452. status = STATUS_SUCCESS;
  1453. }
  1454. break;
  1455. }
  1456. default:
  1457. *OutputParameterCount = 0;
  1458. *OutputDataCount = 0;
  1459. status = STATUS_NOT_SUPPORTED;
  1460. }
  1461. status = STATUS_SUCCESS;
  1462. *OutputParameterCount = 0;
  1463. *OutputDataCount = 0;
  1464. break;
  1465. case SPOOLER_DEVICE:
  1466. IF_SMB_DEBUG( TRANSACTION2 ) {
  1467. KdPrint(( "ProcessOs2Ioctl: spool IOCTL function %lx received.\n",
  1468. Function ));
  1469. }
  1470. switch ( Function ) {
  1471. case GET_PRINTER_ID:
  1472. {
  1473. PUNICODE_STRING shareName = &WorkContext->TreeConnect->Share->ShareName;
  1474. OEM_STRING ansiShare;
  1475. if( MaxOutputData < 2 * (LM20_CNLEN + 1) ) {
  1476. status = STATUS_INVALID_SMB;
  1477. break;
  1478. }
  1479. smbData.PrinterId = (PSMB_IOCTL_PRINTER_ID) Data;
  1480. smbData.PrinterId->JobId = (USHORT)lfcb->JobId;
  1481. buffer = (PCHAR)smbData.PrinterId->Buffer;
  1482. if ( WorkContext->Connection->Endpoint->TransportAddress.Buffer != NULL ) {
  1483. RtlCopyMemory(
  1484. buffer,
  1485. WorkContext->Connection->Endpoint->TransportAddress.Buffer,
  1486. MIN(WorkContext->Connection->Endpoint->TransportAddress.Length+1,LM20_CNLEN)
  1487. );
  1488. } else {
  1489. *buffer = '\0';
  1490. }
  1491. buffer += LM20_CNLEN;
  1492. *buffer++ = '\0';
  1493. status = RtlUnicodeStringToOemString(
  1494. &ansiShare,
  1495. shareName,
  1496. TRUE
  1497. );
  1498. if ( NT_SUCCESS(status) ) {
  1499. if ( ansiShare.Length >= LM20_NNLEN ) {
  1500. RtlCopyMemory(
  1501. buffer,
  1502. ansiShare.Buffer,
  1503. LM20_NNLEN
  1504. );
  1505. } else {
  1506. RtlCopyMemory(
  1507. buffer,
  1508. ansiShare.Buffer,
  1509. ansiShare.Length + 1
  1510. );
  1511. }
  1512. RtlFreeAnsiString(&ansiShare);
  1513. } else {
  1514. *buffer = '\0';
  1515. }
  1516. status = STATUS_SUCCESS;
  1517. buffer += LM20_NNLEN;
  1518. *buffer++ = '\0';
  1519. *OutputParameterCount = 0;
  1520. //
  1521. // data length is equal to the job id +
  1522. // the computer name + the share name + 1
  1523. // I don't know what the last + 1 is for but OS/2
  1524. // sends it.
  1525. //
  1526. *OutputDataCount = sizeof(USHORT) + LM20_CNLEN + 1 +
  1527. LM20_NNLEN + 2;
  1528. }
  1529. break;
  1530. default:
  1531. *OutputParameterCount = 0;
  1532. *OutputDataCount = 0;
  1533. status = STATUS_NOT_SUPPORTED;
  1534. }
  1535. break;
  1536. case GENERAL_DEVICE:
  1537. status = STATUS_NOT_IMPLEMENTED;
  1538. break;
  1539. default:
  1540. // for OS/2 1.x compatibility
  1541. status = STATUS_SUCCESS;
  1542. *OutputParameterCount = 0;
  1543. *OutputDataCount = 0;
  1544. }
  1545. IF_SMB_DEBUG( TRANSACTION2 ) {
  1546. KdPrint( (
  1547. "Category %x, Function %x returns %lx\n",
  1548. Category,
  1549. Function,
  1550. status
  1551. ));
  1552. }
  1553. return status;
  1554. } // ProcessOs2Ioctl