Windows NT 4.0 source code leak
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.

1374 lines
35 KiB

4 years ago
  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. #pragma hdrstop
  15. NTSTATUS
  16. ProcessOs2Ioctl (
  17. IN PWORK_CONTEXT WorkContext,
  18. IN USHORT Category,
  19. IN USHORT Function,
  20. IN PVOID Parameters,
  21. IN ULONG InputParameterCount,
  22. IN PULONG OutputParameterCount,
  23. IN PVOID Data,
  24. IN ULONG InputDataCount,
  25. IN PULONG OutputDataCount
  26. );
  27. VOID SRVFASTCALL
  28. RestartNtIoctl (
  29. IN PWORK_CONTEXT WorkContext
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text( PAGE, SrvSmbIoctl )
  33. #pragma alloc_text( PAGE, SrvSmbIoctlSecondary )
  34. #pragma alloc_text( PAGE, SrvSmbNtIoctl )
  35. #pragma alloc_text( PAGE, RestartNtIoctl )
  36. #pragma alloc_text( PAGE, SrvSmbIoctl2 )
  37. #pragma alloc_text( PAGE, SrvSmbFsctl )
  38. #pragma alloc_text( PAGE, ProcessOs2Ioctl )
  39. #endif
  40. SMB_PROCESSOR_RETURN_TYPE
  41. SrvSmbIoctl (
  42. SMB_PROCESSOR_PARAMETERS
  43. )
  44. /*++
  45. Routine Description:
  46. Processes a primary Ioctl SMB.
  47. Arguments:
  48. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  49. of the parameters to SMB processor routines.
  50. Return Value:
  51. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  52. --*/
  53. {
  54. PREQ_IOCTL request;
  55. PRESP_IOCTL response;
  56. PSMB_HEADER header;
  57. NTSTATUS status;
  58. PSESSION session;
  59. PTREE_CONNECT treeConnect;
  60. PRFCB rfcb;
  61. CLONG parameterOffset;
  62. CLONG parameterCount; // For input on this buffer
  63. CLONG maxParameterCount; // For output
  64. CLONG totalParameterCount; // For input
  65. CLONG parameterSize; // Max of input and output parameter counts
  66. CLONG dataOffset;
  67. CLONG responseDataOffset;
  68. CLONG dataCount; // For input on this buffer
  69. CLONG maxDataCount; // For output
  70. CLONG totalDataCount; // For input
  71. CLONG dataSize; // Max of input and output data counts
  72. CLONG smbLength;
  73. CLONG numberOfPaddings = 0;
  74. PAGED_CODE( );
  75. request = (PREQ_IOCTL)WorkContext->RequestParameters;
  76. response = (PRESP_IOCTL)WorkContext->ResponseParameters;
  77. //
  78. // Since we do I/O from the SMB buffer, verify that the request and
  79. // response buffers are one and the same.
  80. //
  81. ASSERT( (PVOID)request == (PVOID)response );
  82. header = WorkContext->RequestHeader;
  83. IF_SMB_DEBUG(TRANSACTION1) {
  84. KdPrint(( "Ioctl (primary) request\n" ));
  85. }
  86. //
  87. // !!! Verify ioctl subcommand early?
  88. //
  89. parameterOffset = SmbGetUshort( &request->ParameterOffset );
  90. parameterCount = SmbGetUshort( &request->ParameterCount );
  91. maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
  92. totalParameterCount = SmbGetUshort( &request->TotalParameterCount );
  93. dataOffset = SmbGetUshort( &request->DataOffset );
  94. dataCount = SmbGetUshort( &request->DataCount );
  95. maxDataCount = SmbGetUshort( &request->MaxDataCount );
  96. totalDataCount = SmbGetUshort( &request->TotalDataCount );
  97. smbLength = WorkContext->RequestBuffer->DataLength;
  98. dataSize = MAX( dataCount, maxDataCount );
  99. parameterSize = MAX( parameterCount, maxParameterCount );
  100. if ( parameterCount != 0 ) {
  101. responseDataOffset = parameterOffset + parameterSize;
  102. } else {
  103. //
  104. // Some ioctls requests have data offset of zero like
  105. // category 0x53, function 0x60. If this is the case,
  106. // calculate the dataoffset by hand.
  107. //
  108. if ( dataOffset != 0 ) {
  109. responseDataOffset = dataOffset;
  110. } else {
  111. responseDataOffset = (CLONG) ((PUCHAR) response->Buffer -
  112. (PUCHAR) WorkContext->ResponseHeader);
  113. numberOfPaddings = ( responseDataOffset & 0x01 );
  114. responseDataOffset = responseDataOffset + numberOfPaddings;
  115. }
  116. }
  117. //
  118. // Verify the size of the smb buffer:
  119. //
  120. // Even though we know that WordCount and ByteCount are valid, it's
  121. // still possible that the offsets and lengths of the Parameter and
  122. // Data bytes are invalid. So we check them now.
  123. //
  124. // We need room in the smb buffer for the response. Ensure that
  125. // there is enough room.
  126. //
  127. // No ioctl secondary is expected. Ensure that all data and
  128. // parameters have arrrived.
  129. //
  130. // Check that the response will fit in a single buffer.
  131. //
  132. if ( ( (parameterOffset + parameterCount) > smbLength ) ||
  133. ( (dataOffset + dataCount) > smbLength ) ||
  134. ( (responseDataOffset + dataCount) >
  135. WorkContext->ResponseBuffer->BufferLength ) ||
  136. ( dataCount != totalDataCount ) ||
  137. ( parameterCount != totalParameterCount ) ||
  138. ( (parameterOffset > dataOffset) && (dataCount != 0) ) ) {
  139. IF_DEBUG(SMB_ERRORS) {
  140. KdPrint(( "SrvSmbTransaction: Invalid parameter or data "
  141. "offset+count: pOff=%ld,pCnt=%ld;",
  142. parameterOffset, parameterCount ));
  143. KdPrint(( "dOff=%ld,dCnt=%ld;", dataOffset, dataCount ));
  144. KdPrint(( "smbLen=%ld", smbLength ));
  145. }
  146. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  147. return SmbStatusSendResponse;
  148. }
  149. //
  150. // If a session block has not already been assigned to the current
  151. // work context, verify the UID. If verified, the address of the
  152. // session block corresponding to this user is stored in the
  153. // WorkContext block and the session block is referenced.
  154. //
  155. // If a tree connect block has not already been assigned to the
  156. // current work context, find the tree connect corresponding to the
  157. // given TID.
  158. //
  159. status = SrvVerifyUidAndTid(
  160. WorkContext,
  161. &session,
  162. &treeConnect,
  163. ShareTypeWild
  164. );
  165. if ( !NT_SUCCESS(status) ) {
  166. IF_DEBUG(SMB_ERRORS) {
  167. KdPrint(( "SrvSmbIoctl: Invalid UID or TID\n" ));
  168. }
  169. SrvSetSmbError( WorkContext, status );
  170. return SmbStatusSendResponse;
  171. }
  172. //
  173. // Verify the FID. If verified, the RFCB block is referenced
  174. // and its addresses is stored in the WorkContext block, and the
  175. // RFCB address is returned.
  176. //
  177. rfcb = SrvVerifyFid(
  178. WorkContext,
  179. request->Fid,
  180. TRUE,
  181. SrvRestartSmbReceived, // serialize with raw write
  182. &status
  183. );
  184. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  185. if ( !NT_SUCCESS( status ) ) {
  186. //
  187. // Invalid file ID or write behind error. Reject the request.
  188. //
  189. IF_DEBUG(ERRORS) {
  190. KdPrint((
  191. "SrvSmbIoctl: Status %X on FID: 0x%lx\n",
  192. request->Fid,
  193. status
  194. ));
  195. }
  196. SrvSetSmbError( WorkContext, status );
  197. return SmbStatusSendResponse;
  198. }
  199. //
  200. // The work item has been queued because a raw write is in
  201. // progress.
  202. //
  203. return SmbStatusInProgress;
  204. }
  205. //
  206. // Make room in the SMB buffer for return parameters by copying data
  207. //
  208. if ( dataOffset != responseDataOffset && dataCount != 0) {
  209. RtlMoveMemory(
  210. (PCHAR)header + responseDataOffset,
  211. (PCHAR)header + dataOffset,
  212. dataCount
  213. );
  214. }
  215. //
  216. // Process the ioctl. The response will overwrite the request buffer.
  217. //
  218. status = ProcessOs2Ioctl(
  219. WorkContext,
  220. request->Category,
  221. request->Function,
  222. (PCHAR)WorkContext->RequestHeader + parameterOffset,
  223. totalParameterCount,
  224. &maxParameterCount,
  225. (PCHAR)WorkContext->RequestHeader + responseDataOffset,
  226. totalDataCount,
  227. &maxDataCount
  228. );
  229. //
  230. // Format and send the response, the parameter and data bytes are
  231. // already in place.
  232. //
  233. if ( !NT_SUCCESS( status ) ) {
  234. SrvSetSmbError( WorkContext, status );
  235. return SmbStatusSendResponse;
  236. }
  237. response->WordCount = 8;
  238. SmbPutUshort( &response->TotalParameterCount, (USHORT)maxParameterCount );
  239. SmbPutUshort( &response->TotalDataCount, (USHORT)maxDataCount );
  240. SmbPutUshort( &response->ParameterCount, (USHORT)maxParameterCount );
  241. SmbPutUshort( &response->ParameterOffset, (USHORT)parameterOffset );
  242. SmbPutUshort( &response->ParameterDisplacement, 0);
  243. SmbPutUshort( &response->DataCount, (USHORT)maxDataCount );
  244. SmbPutUshort( &response->DataOffset, (USHORT)responseDataOffset );
  245. SmbPutUshort( &response->DataDisplacement, 0 );
  246. SmbPutUshort(
  247. &response->ByteCount,
  248. (USHORT)(maxDataCount + numberOfPaddings)
  249. );
  250. WorkContext->ResponseParameters = NEXT_LOCATION(
  251. response,
  252. RESP_IOCTL,
  253. maxDataCount + numberOfPaddings
  254. );
  255. return SmbStatusSendResponse;
  256. } // SrvSmbIoctl
  257. SMB_PROCESSOR_RETURN_TYPE
  258. SrvSmbIoctlSecondary (
  259. SMB_PROCESSOR_PARAMETERS
  260. )
  261. /*++
  262. Routine Description:
  263. Processes a secondary Ioctl SMB.
  264. Arguments:
  265. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  266. of the parameters to SMB processor routines.
  267. Return Value:
  268. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  269. --*/
  270. {
  271. PAGED_CODE( );
  272. //
  273. // This SMB is not supported.
  274. //
  275. SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
  276. return SmbStatusSendResponse;
  277. }
  278. SMB_TRANS_STATUS
  279. SrvSmbNtIoctl (
  280. SMB_PROCESSOR_PARAMETERS
  281. )
  282. /*++
  283. Routine Description:
  284. Processes a Nt Ioctl SMB.
  285. Arguments:
  286. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  287. of the parameters to SMB processor routines.
  288. Return Value:
  289. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  290. --*/
  291. {
  292. NTSTATUS status;
  293. ULONG functionCode;
  294. USHORT fid;
  295. BOOLEAN isFsctl;
  296. PREQ_NT_IO_CONTROL request;
  297. PTRANSACTION transaction;
  298. PRFCB rfcb;
  299. PMDL mdl = NULL;
  300. PAGED_CODE( );
  301. transaction = WorkContext->Parameters.Transaction;
  302. request = (PREQ_NT_IO_CONTROL)transaction->InSetup;
  303. functionCode = SmbGetAlignedUlong( &request->FunctionCode );
  304. fid = SmbGetAlignedUshort( &request->Fid );
  305. isFsctl = request->IsFsctl;
  306. //
  307. // Verify the FID. If verified, the RFCB block is referenced
  308. // and its addresses is stored in the WorkContext block, and the
  309. // RFCB address is returned.
  310. //
  311. rfcb = SrvVerifyFid(
  312. WorkContext,
  313. fid,
  314. TRUE,
  315. SrvRestartExecuteTransaction, // serialize with raw write
  316. &status
  317. );
  318. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  319. if ( !NT_SUCCESS( status ) ) {
  320. //
  321. // Invalid file ID or write behind error. Reject the request.
  322. //
  323. IF_DEBUG(ERRORS) {
  324. KdPrint((
  325. "SrvSmbNtIoctl: Status %X on FID: 0x%lx\n",
  326. status,
  327. fid
  328. ));
  329. }
  330. SrvSetSmbError( WorkContext, status );
  331. return SmbTransStatusErrorWithoutData;
  332. }
  333. //
  334. // The work item has been queued because a raw write is in
  335. // progress.
  336. //
  337. return SmbTransStatusInProgress;
  338. }
  339. CHECK_FUNCTION_ACCESS(
  340. rfcb->GrantedAccess,
  341. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  342. 0,
  343. functionCode,
  344. &status
  345. );
  346. if ( !NT_SUCCESS( status ) ) {
  347. SrvStatistics.GrantedAccessErrors++;
  348. SrvSetSmbError( WorkContext, status );
  349. return SmbTransStatusErrorWithoutData;
  350. }
  351. //
  352. // Since we are doing ioctls to this file, it doesn't seem like it's
  353. // a "normal" file. We had better not cache its handle after the close.
  354. // Specifically, remote setting of the file's compression state is
  355. // not reflected to the directory entry until the file is closed. And
  356. // setting a file's compression state is done with an ioctl
  357. //
  358. rfcb->IsCacheable = FALSE;
  359. if ( (functionCode & 3) == METHOD_IN_DIRECT ||
  360. (functionCode & 3) == METHOD_OUT_DIRECT ) {
  361. //
  362. // Need an mdl
  363. //
  364. mdl = IoAllocateMdl(
  365. transaction->InData,
  366. transaction->TotalDataCount,
  367. FALSE,
  368. FALSE,
  369. NULL
  370. );
  371. if ( mdl == NULL ) {
  372. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  373. return SmbTransStatusErrorWithoutData;
  374. }
  375. //
  376. // Build the mdl
  377. //
  378. MmProbeAndLockPages(
  379. mdl,
  380. KernelMode,
  381. IoReadAccess
  382. );
  383. }
  384. //
  385. // Set the Restart Routine addresses in the work context block.
  386. //
  387. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  388. WorkContext->FspRestartRoutine = RestartNtIoctl;
  389. //
  390. // Build the IRP to start the I/O control.
  391. // Pass this request to the filesystem.
  392. //
  393. SrvBuildIoControlRequest(
  394. WorkContext->Irp,
  395. rfcb->Lfcb->FileObject,
  396. WorkContext,
  397. (UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
  398. functionCode,
  399. transaction->InData,
  400. transaction->DataCount,
  401. transaction->OutData,
  402. transaction->MaxDataCount,
  403. mdl,
  404. NULL // Completion routine
  405. );
  406. (PVOID)IoCallDriver(
  407. IoGetRelatedDeviceObject(rfcb->Lfcb->FileObject ),
  408. WorkContext->Irp
  409. );
  410. //
  411. // The call was successfully started, return InProgress to the caller
  412. //
  413. return SmbTransStatusInProgress;
  414. } // SrvSmbNtIoctl
  415. VOID SRVFASTCALL
  416. RestartNtIoctl (
  417. IN PWORK_CONTEXT WorkContext
  418. )
  419. /*++
  420. Routine Description:
  421. This function handles the completion of an NT Io control SMB.
  422. Arguments:
  423. WorkContext - A pointer to a WORK_CONTEXT block.
  424. Return Value:
  425. None.
  426. --*/
  427. {
  428. NTSTATUS status;
  429. ULONG length;
  430. PTRANSACTION transaction;
  431. PAGED_CODE( );
  432. //
  433. // Free the MDL if one was allocated.
  434. //
  435. if ( WorkContext->Irp->MdlAddress != NULL ) {
  436. IoFreeMdl( WorkContext->Irp->MdlAddress );
  437. }
  438. //
  439. // If the Io Control request failed, set an error status in the response
  440. // header.
  441. //
  442. status = WorkContext->Irp->IoStatus.Status;
  443. if ( NT_ERROR(status) ) {
  444. IF_DEBUG(ERRORS) {
  445. KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
  446. status ));
  447. }
  448. SrvSetSmbError( WorkContext, status );
  449. SrvCompleteExecuteTransaction(
  450. WorkContext,
  451. SmbTransStatusErrorWithoutData
  452. );
  453. } else {
  454. //
  455. // Success. Prepare to generate and send the response.
  456. //
  457. transaction = WorkContext->Parameters.Transaction;
  458. length = MIN( WorkContext->Irp->IoStatus.Information, transaction->MaxDataCount );
  459. if ( transaction->MaxSetupCount > 0 ) {
  460. transaction->SetupCount = 1;
  461. SmbPutUshort( transaction->OutSetup, (USHORT)length );
  462. }
  463. transaction->ParameterCount = transaction->MaxParameterCount;
  464. transaction->DataCount = length;
  465. if (!NT_SUCCESS(status) ) {
  466. IF_DEBUG(ERRORS) {
  467. KdPrint(( "RestartNtIoctl: Io control failed: %lC\n",
  468. status ));
  469. }
  470. SrvSetSmbError2( WorkContext, status, TRUE );
  471. SrvCompleteExecuteTransaction(
  472. WorkContext,
  473. SmbTransStatusErrorWithData
  474. );
  475. } else {
  476. SrvCompleteExecuteTransaction(
  477. WorkContext,
  478. SmbTransStatusSuccess);
  479. }
  480. }
  481. return;
  482. } // RestartNtIoctl
  483. SMB_TRANS_STATUS
  484. SrvSmbIoctl2 (
  485. IN OUT PWORK_CONTEXT WorkContext
  486. )
  487. /*++
  488. Routine Description:
  489. Processes the Ioctl request. This request arrives in a Transaction2 SMB.
  490. Arguments:
  491. WorkContext - Supplies the address of a Work Context Block
  492. describing the current request. See smbtypes.h for a more
  493. complete description of the valid fields.
  494. Return Value:
  495. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  496. whether data should be returned to the client. See smbtypes.h
  497. for a more complete description.
  498. --*/
  499. {
  500. NTSTATUS status;
  501. PTRANSACTION transaction;
  502. PRFCB rfcb;
  503. PAGED_CODE( );
  504. transaction = WorkContext->Parameters.Transaction;
  505. IF_SMB_DEBUG(TRANSACTION2) {
  506. KdPrint(( "Ioctl2 entered; transaction 0x%lx\n",
  507. transaction ));
  508. }
  509. //request = (PREQ_IOCTL2)transaction->InSetup;
  510. //
  511. // Verify the setup count.
  512. //
  513. if ( transaction->SetupCount != 4 * sizeof( USHORT ) ) {
  514. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  515. return SmbTransStatusErrorWithoutData;
  516. }
  517. //
  518. // Verify the FID. If verified, the RFCB block is referenced
  519. // and its addresses is stored in the WorkContext block, and the
  520. // RFCB address is returned.
  521. //
  522. rfcb = SrvVerifyFid(
  523. WorkContext,
  524. transaction->InSetup[1],
  525. TRUE,
  526. SrvRestartExecuteTransaction, // serialize with raw write
  527. &status
  528. );
  529. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  530. if ( !NT_SUCCESS( status ) ) {
  531. //
  532. // Invalid file ID or write behind error. Reject the request.
  533. //
  534. IF_DEBUG(ERRORS) {
  535. KdPrint((
  536. "SrvSmbIoctl2: Status %X on FID: 0x%lx\n",
  537. transaction->InSetup[1],
  538. status
  539. ));
  540. }
  541. SrvSetSmbError( WorkContext, status );
  542. return SmbTransStatusErrorWithoutData;
  543. }
  544. //
  545. // The work item has been queued because a raw write is in
  546. // progress.
  547. //
  548. return SmbTransStatusInProgress;
  549. }
  550. transaction->Category = transaction->InSetup[2];
  551. transaction->Function = transaction->InSetup[3];
  552. //
  553. // Perform the Ioctl
  554. //
  555. status = ProcessOs2Ioctl(
  556. WorkContext,
  557. transaction->InSetup[2],
  558. transaction->InSetup[3],
  559. transaction->InParameters,
  560. transaction->ParameterCount,
  561. &transaction->MaxParameterCount,
  562. transaction->OutData,
  563. transaction->DataCount,
  564. &transaction->MaxDataCount
  565. );
  566. //
  567. // If an error occurred, return an appropriate response.
  568. //
  569. if ( !NT_SUCCESS(status) ) {
  570. SrvSetSmbError( WorkContext, status );
  571. return SmbTransStatusErrorWithoutData;
  572. }
  573. transaction->SetupCount = 0;
  574. transaction->ParameterCount = transaction->MaxParameterCount;
  575. transaction->DataCount = transaction->MaxDataCount;
  576. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbIoctl2 complete.\n" ));
  577. return SmbTransStatusSuccess;
  578. } // SrvSmbIoctl2
  579. SMB_TRANS_STATUS
  580. SrvSmbFsctl (
  581. IN OUT PWORK_CONTEXT WorkContext
  582. )
  583. {
  584. PAGED_CODE( );
  585. //
  586. // The OS/2 redirector never sends a remote FS control request.
  587. // If we get one, simply reply that we cannot handle it.
  588. //
  589. return SrvTransactionNotImplemented( WorkContext );
  590. } // SrvSmbFsctl
  591. //
  592. // !!! MOVE THESE
  593. //
  594. #define SERIAL_DEVICE 0x1
  595. #define PRINTER_DEVICE 0x5
  596. #define GENERAL_DEVICE 0xB
  597. #define SPOOLER_DEVICE 0x53
  598. //
  599. // Serial device functions supported
  600. //
  601. #define SET_BAUD_RATE 0x41
  602. #define SET_LINE_CONTROL 0x42
  603. #define SET_TRANSMIT_TIMEOUT 0x44
  604. #define SET_BREAK_OFF 0x45
  605. #define SET_MODEM_CONTROL 0x46
  606. #define SET_BREAK_ON 0x4B
  607. #define STOP_TRANSMIT 0x47
  608. #define START_TRANSMIT 0x48
  609. #define SET_DCB_INFORMATION 0x53
  610. #define GET_BAUD_RATE 0x61
  611. #define GET_LINE_CONTROL 0x62
  612. #define GET_COMM_STATUS 0x64
  613. #define GET_LINE_STATUS 0x65
  614. #define GET_MODEM_OUTPUT 0x66
  615. #define GET_MODEM_INPUT 0x67
  616. #define GET_INQUEUE_COUNT 0x68
  617. #define GET_OUTQUEUE_COUNT 0x69
  618. #define GET_COMM_ERROR 0x6D
  619. #define GET_COMM_EVENT 0x72
  620. #define GET_DCB_INFORMATION 0x73
  621. //
  622. // Print device function supported.
  623. //
  624. // *** Note: The OS/2 server supports 2 additional Ioctl functions.
  625. // ActivateFont (0x48) and QueryActiveFont (0x69). Since these
  626. // were designed only to support IBM proplus printer from OS/2
  627. // and we can't correctly support these function, we don't.
  628. //
  629. #define GET_PRINTER_ID 0x60
  630. #define GET_PRINTER_STATUS 0x66
  631. #define OS2_STATUS_PRINTER_HAPPY 0x90
  632. typedef struct _SMB_IOCTL_LINECONTROL {
  633. UCHAR DataBits;
  634. UCHAR Parity;
  635. UCHAR StopBits;
  636. UCHAR TransBreak;
  637. } SMB_IOCTL_LINE_CONTROL, *PSMB_IOCTL_LINE_CONTROL;
  638. typedef struct _SMB_IOCTL_BAUD_RATE {
  639. USHORT BaudRate;
  640. } SMB_IOCTL_BAUD_RATE, *PSMB_IOCTL_BAUD_RATE;
  641. typedef struct _SMB_IOCTL_DEVICE_CONTROL {
  642. USHORT WriteTimeout;
  643. USHORT ReadTimeout;
  644. UCHAR ControlHandShake;
  645. UCHAR FlowReplace;
  646. UCHAR Timeout;
  647. UCHAR ErrorReplacementChar;
  648. UCHAR BreakReplacementChar;
  649. UCHAR XonChar;
  650. UCHAR XoffChar;
  651. } SMB_IOCTL_DEVICE_CONTROL, *PSMB_IOCTL_DEVICE_CONTROL;
  652. typedef struct _SMB_IOCTL_COMM_ERROR {
  653. USHORT Error;
  654. } SMB_IOCTL_COMM_ERROR, *PSMB_IOCTL_COMM_ERROR;
  655. typedef struct _SMB_IOCTL_PRINTER_ID {
  656. USHORT JobId;
  657. UCHAR Buffer[1]; // server name and share name
  658. } SMB_IOCTL_PRINTER_ID;
  659. typedef SMB_IOCTL_PRINTER_ID SMB_UNALIGNED *PSMB_IOCTL_PRINTER_ID;
  660. NTSTATUS
  661. ProcessOs2Ioctl (
  662. IN PWORK_CONTEXT WorkContext,
  663. IN USHORT Category,
  664. IN USHORT Function,
  665. IN PVOID Parameters,
  666. IN ULONG InputParameterCount,
  667. IN OUT PULONG OutputParameterCount,
  668. IN PVOID Data,
  669. IN ULONG InputDataCount,
  670. IN OUT PULONG OutputDataCount
  671. )
  672. /*++
  673. Routine Description:
  674. This function handles an OS/2 ioctl. It convert the Ioctl SMB data
  675. into an NT ioctl call, makes the call, and format the returned data
  676. into Ioctl SMB return data.
  677. Arguments:
  678. WorkContext
  679. Category
  680. Function
  681. Parameters
  682. InputParameterCount
  683. OutputParameterCount
  684. Data
  685. InputDataCount
  686. OutputDataCount
  687. Return Value:
  688. NTSTATUS
  689. --*/
  690. {
  691. IO_STATUS_BLOCK ioStatusBlock;
  692. NTSTATUS status;
  693. PCHAR buffer;
  694. PLFCB lfcb = WorkContext->Rfcb->Lfcb;
  695. HANDLE Handle = lfcb->FileHandle;
  696. union NT_PARAMTERS {
  697. SERIAL_BAUD_RATE BaudRate;
  698. SERIAL_LINE_CONTROL LineControl;
  699. SERIAL_TIMEOUTS Timeouts;
  700. SERIAL_QUEUE_SIZE QueueSize;
  701. ULONG WaitMask;
  702. ULONG PurgeMask;
  703. UCHAR ImmediateChar;
  704. UCHAR Reserved[3];
  705. SERIAL_CHARS Chars;
  706. SERIAL_HANDFLOW Handflow;
  707. SERIAL_STATUS SerialStatus;
  708. } ntBuffer;
  709. union SMB_PARAMETERS {
  710. PSMB_IOCTL_BAUD_RATE BaudRate;
  711. PSMB_IOCTL_LINE_CONTROL LineControl;
  712. PSMB_IOCTL_DEVICE_CONTROL DeviceControl;
  713. PSMB_IOCTL_COMM_ERROR CommError;
  714. PSMB_IOCTL_PRINTER_ID PrinterId;
  715. } smbParameters, smbData;
  716. PAGED_CODE( );
  717. InputParameterCount, InputDataCount;
  718. switch ( Category ) {
  719. case SERIAL_DEVICE:
  720. switch ( Function ) {
  721. case GET_BAUD_RATE:
  722. status = NtDeviceIoControlFile(
  723. Handle,
  724. 0,
  725. NULL,
  726. NULL,
  727. &ioStatusBlock,
  728. IOCTL_SERIAL_GET_BAUD_RATE,
  729. NULL,
  730. 0,
  731. &ntBuffer,
  732. sizeof( SERIAL_BAUD_RATE )
  733. );
  734. //
  735. // Convert the response to OS/2 format.
  736. //
  737. // !!! ULONG to USHORT conversion.
  738. //
  739. smbData.BaudRate = (PSMB_IOCTL_BAUD_RATE)Data;
  740. if ( NT_SUCCESS( status ) ) {
  741. smbData.BaudRate->BaudRate = (USHORT) ntBuffer.BaudRate.BaudRate;
  742. *OutputParameterCount = 0;
  743. *OutputDataCount = sizeof( SMB_IOCTL_BAUD_RATE );
  744. }
  745. break;
  746. case SET_BAUD_RATE:
  747. //
  748. // Convert the request to NT format.
  749. //
  750. smbParameters.BaudRate =
  751. (PSMB_IOCTL_BAUD_RATE)Parameters;
  752. ntBuffer.BaudRate.BaudRate = smbParameters.BaudRate->BaudRate;
  753. status = NtDeviceIoControlFile(
  754. Handle,
  755. 0,
  756. NULL,
  757. NULL,
  758. &ioStatusBlock,
  759. IOCTL_SERIAL_SET_BAUD_RATE,
  760. &ntBuffer,
  761. sizeof( SERIAL_BAUD_RATE ),
  762. NULL,
  763. 0
  764. );
  765. *OutputParameterCount = 0;
  766. *OutputDataCount = 0;
  767. break;
  768. case SET_LINE_CONTROL:
  769. //
  770. // Convert the request to NT format.
  771. //
  772. smbParameters.LineControl =
  773. (PSMB_IOCTL_LINE_CONTROL)Parameters;
  774. ntBuffer.LineControl.StopBits = smbParameters.LineControl->StopBits;
  775. ntBuffer.LineControl.Parity = smbParameters.LineControl->Parity;
  776. ntBuffer.LineControl.WordLength = smbParameters.LineControl->DataBits;
  777. // !!! What about TransmitBreak?
  778. status = NtDeviceIoControlFile(
  779. Handle,
  780. 0,
  781. NULL,
  782. NULL,
  783. &ioStatusBlock,
  784. IOCTL_SERIAL_SET_LINE_CONTROL,
  785. &ntBuffer,
  786. sizeof( SERIAL_LINE_CONTROL ),
  787. NULL,
  788. 0
  789. );
  790. *OutputParameterCount = 0;
  791. *OutputDataCount = 0;
  792. break;
  793. case GET_LINE_CONTROL:
  794. smbData.LineControl = (PSMB_IOCTL_LINE_CONTROL)Data;
  795. status = NtDeviceIoControlFile(
  796. Handle,
  797. 0,
  798. NULL,
  799. NULL,
  800. &ioStatusBlock,
  801. IOCTL_SERIAL_GET_LINE_CONTROL,
  802. NULL,
  803. 0,
  804. &ntBuffer,
  805. sizeof( SERIAL_LINE_CONTROL )
  806. );
  807. //
  808. // Convert the response to OS/2 format.
  809. //
  810. if ( NT_SUCCESS( status ) ) {
  811. smbData.LineControl->DataBits = ntBuffer.LineControl.WordLength;
  812. smbData.LineControl->Parity = ntBuffer.LineControl.Parity;
  813. smbData.LineControl->StopBits = ntBuffer.LineControl.StopBits;
  814. smbData.LineControl->TransBreak = 0; // !!!
  815. *OutputParameterCount = 0;
  816. *OutputDataCount = sizeof( SMB_IOCTL_LINE_CONTROL );
  817. }
  818. break;
  819. case GET_DCB_INFORMATION:
  820. smbData.DeviceControl =
  821. (PSMB_IOCTL_DEVICE_CONTROL)Data;
  822. status = NtDeviceIoControlFile(
  823. Handle,
  824. 0,
  825. NULL,
  826. NULL,
  827. &ioStatusBlock,
  828. IOCTL_SERIAL_GET_TIMEOUTS,
  829. NULL,
  830. 0,
  831. &ntBuffer,
  832. sizeof( SERIAL_TIMEOUTS )
  833. );
  834. //
  835. // Convert the response to OS/2 format.
  836. //
  837. // !!! Verify units are correct
  838. if ( NT_SUCCESS( status ) ) {
  839. smbData.DeviceControl->WriteTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout; // !!!
  840. smbData.DeviceControl->ReadTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout;
  841. } else {
  842. break;
  843. }
  844. status = NtDeviceIoControlFile(
  845. Handle,
  846. 0,
  847. NULL,
  848. NULL,
  849. &ioStatusBlock,
  850. IOCTL_SERIAL_GET_TIMEOUTS,
  851. NULL,
  852. 0,
  853. &ntBuffer,
  854. sizeof( SERIAL_TIMEOUTS )
  855. );
  856. //
  857. // Convert the response to OS/2 format.
  858. //
  859. if ( NT_SUCCESS( status ) ) {
  860. smbData.DeviceControl->XonChar = ntBuffer.Chars.XonChar;
  861. smbData.DeviceControl->XoffChar = ntBuffer.Chars.XoffChar;
  862. smbData.DeviceControl->ErrorReplacementChar = ntBuffer.Chars.ErrorChar;
  863. smbData.DeviceControl->BreakReplacementChar = ntBuffer.Chars.BreakChar;
  864. } else {
  865. break;
  866. }
  867. smbData.DeviceControl->ControlHandShake = 0; // !!!
  868. smbData.DeviceControl->FlowReplace = 0; // !!!
  869. smbData.DeviceControl->Timeout = 0; // !!!
  870. *OutputParameterCount = 0;
  871. *OutputDataCount = sizeof( SMB_IOCTL_DEVICE_CONTROL );
  872. break;
  873. case SET_DCB_INFORMATION:
  874. //
  875. // Lie. Pretend this succeeded.
  876. //
  877. status = STATUS_SUCCESS;
  878. *OutputParameterCount = 0;
  879. *OutputDataCount = 0;
  880. break;
  881. case GET_COMM_ERROR:
  882. //
  883. // Pretend that there is no comm error.
  884. //
  885. smbData.CommError = (PSMB_IOCTL_COMM_ERROR)Data;
  886. status = STATUS_SUCCESS;
  887. if ( NT_SUCCESS( status ) ) {
  888. smbData.CommError->Error = 0;
  889. *OutputParameterCount = 0;
  890. *OutputDataCount = sizeof( SMB_IOCTL_COMM_ERROR );
  891. }
  892. break;
  893. case SET_TRANSMIT_TIMEOUT:
  894. case SET_BREAK_OFF:
  895. case SET_MODEM_CONTROL:
  896. case SET_BREAK_ON:
  897. case STOP_TRANSMIT:
  898. case START_TRANSMIT:
  899. case GET_COMM_STATUS:
  900. case GET_LINE_STATUS:
  901. case GET_MODEM_OUTPUT:
  902. case GET_MODEM_INPUT:
  903. case GET_INQUEUE_COUNT:
  904. case GET_OUTQUEUE_COUNT:
  905. case GET_COMM_EVENT:
  906. status = STATUS_NOT_IMPLEMENTED;
  907. break;
  908. default:
  909. status = STATUS_INVALID_PARAMETER;
  910. }
  911. break;
  912. case PRINTER_DEVICE:
  913. IF_SMB_DEBUG( TRANSACTION2 ) {
  914. KdPrint(( "ProcessOs2Ioctl: print IOCTL function %lx received.\n",
  915. Function ));
  916. }
  917. switch ( Function ) {
  918. case GET_PRINTER_STATUS:
  919. *OutputParameterCount = 0;
  920. *OutputDataCount = 0;
  921. if ( *(PCHAR)Parameters != 0 ) {
  922. status = STATUS_INVALID_PARAMETER;
  923. } else {
  924. //
  925. // Always return STATUS_PRINTER_HAPPY
  926. //
  927. *(PCHAR)Data = (CHAR)OS2_STATUS_PRINTER_HAPPY;
  928. *OutputParameterCount = 0;
  929. *OutputDataCount = sizeof( CHAR );
  930. status = STATUS_SUCCESS;
  931. break;
  932. }
  933. default:
  934. *OutputParameterCount = 0;
  935. *OutputDataCount = 0;
  936. status = STATUS_NOT_SUPPORTED;
  937. }
  938. status = STATUS_SUCCESS;
  939. *OutputParameterCount = 0;
  940. *OutputDataCount = 0;
  941. break;
  942. case SPOOLER_DEVICE:
  943. IF_SMB_DEBUG( TRANSACTION2 ) {
  944. KdPrint(( "ProcessOs2Ioctl: spool IOCTL function %lx received.\n",
  945. Function ));
  946. }
  947. switch ( Function ) {
  948. case GET_PRINTER_ID:
  949. {
  950. PUNICODE_STRING shareName = &WorkContext->TreeConnect->Share->ShareName;
  951. OEM_STRING ansiShare;
  952. smbData.PrinterId = (PSMB_IOCTL_PRINTER_ID) Data;
  953. smbData.PrinterId->JobId = (USHORT)lfcb->JobId;
  954. buffer = (PCHAR)smbData.PrinterId->Buffer;
  955. if ( WorkContext->Connection->Endpoint->TransportAddress.Buffer != NULL ) {
  956. RtlCopyMemory(
  957. buffer,
  958. WorkContext->Connection->Endpoint->TransportAddress.Buffer,
  959. MIN(WorkContext->Connection->Endpoint->TransportAddress.Length+1,LM20_CNLEN)
  960. );
  961. } else {
  962. *buffer = '\0';
  963. }
  964. buffer += LM20_CNLEN;
  965. *buffer++ = '\0';
  966. status = RtlUnicodeStringToOemString(
  967. &ansiShare,
  968. shareName,
  969. TRUE
  970. );
  971. if ( NT_SUCCESS(status) ) {
  972. if ( ansiShare.Length >= LM20_NNLEN ) {
  973. RtlCopyMemory(
  974. buffer,
  975. ansiShare.Buffer,
  976. LM20_NNLEN
  977. );
  978. } else {
  979. RtlCopyMemory(
  980. buffer,
  981. ansiShare.Buffer,
  982. ansiShare.Length + 1
  983. );
  984. }
  985. RtlFreeAnsiString(&ansiShare);
  986. } else {
  987. *buffer = '\0';
  988. }
  989. status = STATUS_SUCCESS;
  990. buffer += LM20_NNLEN;
  991. *buffer++ = '\0';
  992. *OutputParameterCount = 0;
  993. //
  994. // data length is equal to the job id +
  995. // the computer name + the share name + 1
  996. // I don't know what the last + 1 is for but OS/2
  997. // sends it.
  998. //
  999. *OutputDataCount = sizeof(USHORT) + LM20_CNLEN + 1 +
  1000. LM20_NNLEN + 2;
  1001. }
  1002. break;
  1003. default:
  1004. *OutputParameterCount = 0;
  1005. *OutputDataCount = 0;
  1006. status = STATUS_NOT_SUPPORTED;
  1007. }
  1008. break;
  1009. case GENERAL_DEVICE:
  1010. status = STATUS_NOT_IMPLEMENTED;
  1011. break;
  1012. default:
  1013. // for OS/2 1.x compatibility
  1014. status = STATUS_SUCCESS;
  1015. *OutputParameterCount = 0;
  1016. *OutputDataCount = 0;
  1017. }
  1018. IF_SMB_DEBUG( TRANSACTION2 ) {
  1019. KdPrint( (
  1020. "Category %x, Function %x returns %lx\n",
  1021. Category,
  1022. Function,
  1023. status
  1024. ));
  1025. }
  1026. return status;
  1027. } // ProcessOs2Ioctl