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.

2350 lines
68 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbmisc.c
  5. Abstract:
  6. This module contains routines for processing MISC class SMBs:
  7. Echo
  8. Query FS Information
  9. Set FS Information
  10. Query Disk Information
  11. Author:
  12. Chuck Lenzmeier (chuckl) 9-Nov-1989
  13. David Treadwell (davidtr)
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. #include "smbmisc.tmh"
  18. #pragma hdrstop
  19. #define BugCheckFileId SRV_FILE_SMBMISC
  20. STATIC
  21. ULONG QueryVolumeInformation[] = {
  22. SMB_QUERY_FS_LABEL_INFO, // Base level
  23. FileFsLabelInformation, // Mapping for base level
  24. FileFsVolumeInformation,
  25. FileFsSizeInformation,
  26. FileFsDeviceInformation,
  27. FileFsAttributeInformation
  28. };
  29. STATIC
  30. VOID SRVFASTCALL
  31. RestartEcho (
  32. IN OUT PWORK_CONTEXT WorkContext
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text( PAGE, SrvSmbEcho )
  36. #pragma alloc_text( PAGE, RestartEcho )
  37. #pragma alloc_text( PAGE, SrvSmbQueryFsInformation )
  38. #pragma alloc_text( PAGE, SrvSmbSetFsInformation )
  39. #pragma alloc_text( PAGE, SrvSmbQueryInformationDisk )
  40. #pragma alloc_text( PAGE, SrvSmbSetSecurityDescriptor )
  41. #pragma alloc_text( PAGE, SrvSmbQuerySecurityDescriptor )
  42. #pragma alloc_text( PAGE, SrvSmbQueryQuota )
  43. #pragma alloc_text( PAGE, SrvSmbSetQuota )
  44. #endif
  45. #if 0
  46. NOT PAGEABLE -- SrvSmbNtCancel
  47. #endif
  48. SMB_PROCESSOR_RETURN_TYPE
  49. SrvSmbEcho (
  50. SMB_PROCESSOR_PARAMETERS
  51. )
  52. /*++
  53. Routine Description:
  54. Processes an Echo SMB. It sends the first echo, if any, specifying
  55. RestartEcho as the restart routine. That routine sends the
  56. remaining echoes.
  57. Arguments:
  58. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  59. of the parameters to SMB processor routines.
  60. Return Value:
  61. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  62. --*/
  63. {
  64. PREQ_ECHO request;
  65. PRESP_ECHO response;
  66. SMB_STATUS SmbStatus = SmbStatusInProgress;
  67. PAGED_CODE( );
  68. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  69. WorkContext->PreviousSMB = EVENT_TYPE_SMB_ECHO;
  70. SrvWmiStartContext(WorkContext);
  71. request = (PREQ_ECHO)WorkContext->RequestParameters;
  72. response = (PRESP_ECHO)WorkContext->ResponseParameters;
  73. //
  74. // If the echo count is 0, there are no echoes to send.
  75. //
  76. if ( SmbGetUshort( &request->EchoCount ) == 0 ) {
  77. SmbStatus = SmbStatusNoResponse;
  78. goto Cleanup;
  79. }
  80. //
  81. // The echo count is not zero. Save it in the work context, then
  82. // send the first echo.
  83. //
  84. // *** This code depends on the response buffer being the same as
  85. // the request buffer. It does not copy the echo data from the
  86. // request to the response. It does not update the DataLength
  87. // of the response buffer.
  88. //
  89. // !!! Need to put in code to verify the requested TID, if any.
  90. //
  91. SrvReleaseContext( WorkContext );
  92. WorkContext->Parameters.RemainingEchoCount =
  93. (USHORT)(SmbGetUshort( &request->EchoCount ) - 1);
  94. ASSERT( WorkContext->ResponseHeader == WorkContext->RequestHeader );
  95. SmbPutUshort( &response->SequenceNumber, 1 );
  96. //
  97. // Set the bit in the SMB that indicates this is a response from the
  98. // server.
  99. //
  100. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  101. //
  102. // Send the echo. Notice that the smb statistics will be updated
  103. // here. Instead of measuring the time to finish all the echos,
  104. // we just measure the time to respond to the first. This will
  105. // save us the trouble of storing the timestamp somewhere.
  106. //
  107. SRV_START_SEND_2(
  108. WorkContext,
  109. SrvQueueWorkToFspAtSendCompletion,
  110. NULL,
  111. RestartEcho
  112. );
  113. //
  114. // The echo has been started. Tell the main SMB processor not to
  115. // do anything more with the current SMB.
  116. //
  117. SmbStatus = SmbStatusInProgress;
  118. Cleanup:
  119. SrvWmiEndContext(WorkContext);
  120. return SmbStatus;
  121. } // SrvSmbEcho
  122. VOID SRVFASTCALL
  123. RestartEcho (
  124. IN PWORK_CONTEXT WorkContext
  125. )
  126. /*++
  127. Routine Description:
  128. Processes send completion for an Echo. If more echoes are required,
  129. it sends the next one.
  130. Arguments:
  131. WorkContext - Supplies a pointer to the work context block
  132. describing server-specific context for the request.
  133. Return Value:
  134. None.
  135. --*/
  136. {
  137. PCONNECTION connection;
  138. PAGED_CODE( );
  139. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  140. WorkContext->PreviousSMB = EVENT_TYPE_SMB_ECHO;
  141. SrvWmiStartContext(WorkContext);
  142. IF_DEBUG(WORKER1) SrvPrint0( " - RestartEcho\n" );
  143. //
  144. // Get the connection pointer. The connection pointer is a
  145. // referenced pointer. (The endpoint is valid because the
  146. // connection references the endpoint.)
  147. //
  148. connection = WorkContext->Connection;
  149. IF_DEBUG(TRACE2) SrvPrint2( " connection %p, endpoint %p\n",
  150. connection, WorkContext->Endpoint );
  151. //
  152. // If the I/O request failed or was canceled, or if the connection
  153. // is no longer active, clean up. (The connection is marked as
  154. // closing when it is disconnected or when the endpoint is closed.)
  155. //
  156. // !!! If I/O failure, should we drop the connection?
  157. //
  158. if ( WorkContext->Irp->Cancel ||
  159. !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ||
  160. (GET_BLOCK_STATE(connection) != BlockStateActive) ) {
  161. IF_DEBUG(TRACE2) {
  162. if ( WorkContext->Irp->Cancel ) {
  163. SrvPrint0( " I/O canceled\n" );
  164. } else if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  165. SrvPrint1( " I/O failed: %X\n",
  166. WorkContext->Irp->IoStatus.Status );
  167. } else {
  168. SrvPrint0( " Connection no longer active\n" );
  169. }
  170. }
  171. //
  172. // Indicate that SMB processing is complete.
  173. //
  174. SrvEndSmbProcessing( WorkContext, SmbStatusNoResponse );
  175. IF_DEBUG(TRACE2) SrvPrint0( "RestartEcho complete\n" );
  176. goto Cleanup;
  177. }
  178. //
  179. // The request was successful, and the connection is still active.
  180. // If there are no more echoes to be sent, indicate that SMB
  181. // processing is complete.
  182. //
  183. if ( WorkContext->Parameters.RemainingEchoCount == 0 ) {
  184. SrvEndSmbProcessing( WorkContext, SmbStatusNoResponse );
  185. IF_DEBUG(TRACE2) SrvPrint0( "RestartEcho complete\n" );
  186. goto Cleanup;
  187. }
  188. --WorkContext->Parameters.RemainingEchoCount;
  189. //
  190. // There are more echoes to be sent. Increment the sequence number
  191. // in the response SMB, and send another echo.
  192. //
  193. SmbPutUshort(
  194. &((PRESP_ECHO)WorkContext->ResponseParameters)->SequenceNumber,
  195. (USHORT)(SmbGetUshort(
  196. &((PRESP_ECHO)WorkContext->ResponseParameters)->SequenceNumber
  197. ) + 1)
  198. );
  199. //
  200. // Don't do smb statistics a second time.
  201. //
  202. WorkContext->StartTime = 0;
  203. //
  204. // Send the echo. (Note that the response bit has already been
  205. // set.)
  206. //
  207. SRV_START_SEND_2(
  208. WorkContext,
  209. SrvQueueWorkToFspAtSendCompletion,
  210. NULL,
  211. RestartEcho
  212. );
  213. IF_DEBUG(TRACE2) SrvPrint0( "RestartEcho complete\n" );
  214. Cleanup:
  215. SrvWmiEndContext(WorkContext);
  216. return;
  217. } // RestartEcho
  218. SMB_TRANS_STATUS
  219. SrvSmbQueryFsInformation (
  220. IN OUT PWORK_CONTEXT WorkContext
  221. )
  222. /*++
  223. Routine Description:
  224. Processes the Query FS Information request. This request arrives
  225. in a Transaction2 SMB. Query FS Information corresponds to the
  226. OS/2 DosQFSInfo service.
  227. Arguments:
  228. WorkContext - Supplies the address of a Work Context Block
  229. describing the current request. See smbtypes.h for a more
  230. complete description of the valid fields.
  231. Return Value:
  232. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  233. whether data should be returned to the client. See smbtypes.h
  234. for a more complete description.
  235. --*/
  236. {
  237. NTSTATUS status = STATUS_SUCCESS;
  238. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  239. IO_STATUS_BLOCK ioStatusBlock;
  240. PTRANSACTION transaction;
  241. USHORT informationLevel;
  242. USHORT trans2code;
  243. HANDLE fileHandle;
  244. FILE_FS_SIZE_INFORMATION fsSizeInfo;
  245. PFSALLOCATE fsAllocate;
  246. PFILE_FS_VOLUME_INFORMATION fsVolumeInfo;
  247. ULONG fsVolumeInfoLength;
  248. PFSINFO fsInfo;
  249. ULONG lengthVolumeLabel;
  250. BOOLEAN isUnicode;
  251. PREQ_QUERY_FS_INFORMATION request;
  252. PAGED_CODE( );
  253. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  254. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_FS_INFORMATION;
  255. SrvWmiStartContext(WorkContext);
  256. isUnicode = SMB_IS_UNICODE( WorkContext );
  257. transaction = WorkContext->Parameters.Transaction;
  258. IF_SMB_DEBUG(MISC1) {
  259. SrvPrint1( "Query FS Information entered; transaction 0x%p\n",
  260. transaction );
  261. }
  262. //
  263. // Verify that enough parameter bytes were sent and that we're allowed
  264. // to return enough parameter bytes. Query FS information has no
  265. // response parameters.
  266. //
  267. if ( (transaction->ParameterCount < sizeof(REQ_QUERY_FS_INFORMATION)) ) {
  268. //
  269. // Not enough parameter bytes were sent.
  270. //
  271. IF_DEBUG(SMB_ERRORS) {
  272. SrvPrint2( "SrvSmbQueryFSInformation: bad parameter byte "
  273. "counts: %ld %ld\n",
  274. transaction->ParameterCount,
  275. transaction->MaxParameterCount );
  276. }
  277. SrvLogInvalidSmb( WorkContext );
  278. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  279. status = STATUS_INVALID_SMB;
  280. SmbStatus = SmbTransStatusErrorWithoutData;
  281. goto Cleanup;
  282. }
  283. //
  284. // See if a non-admin user is trying to access information on an Administrative share
  285. //
  286. status = SrvIsAllowedOnAdminShare( WorkContext, WorkContext->TreeConnect->Share );
  287. if( !NT_SUCCESS( status ) ) {
  288. SrvSetSmbError( WorkContext, status );
  289. SmbStatus = SmbTransStatusErrorWithoutData;
  290. goto Cleanup;
  291. }
  292. trans2code = SmbGetAlignedUshort(transaction->InSetup);
  293. IF_SMB_DEBUG(MISC1) {
  294. SrvPrint1("SrvSmbQueryFSInformation: Trans2 function = %x\n", trans2code);
  295. }
  296. request = (PREQ_QUERY_FS_INFORMATION) transaction->InParameters;
  297. ASSERT( trans2code == TRANS2_QUERY_FS_INFORMATION );
  298. informationLevel = SmbGetUshort( &request->InformationLevel );
  299. //
  300. // *** The share handle is used to get the allocation
  301. // information. This is a "storage channel," and as a
  302. // result could allow people to get information to which
  303. // they are not entitled. For a B2 security rating this may
  304. // need to be changed.
  305. //
  306. status = SrvGetShareRootHandle( WorkContext->TreeConnect->Share );
  307. if (!NT_SUCCESS(status)) {
  308. IF_DEBUG(ERRORS) {
  309. SrvPrint1( "SrvSmbQueryFsInformation: SrvGetShareRootHandle failed %x.\n",
  310. status );
  311. }
  312. SrvSetSmbError( WorkContext, status );
  313. SmbStatus = SmbTransStatusErrorWithoutData;
  314. goto Cleanup;
  315. }
  316. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  317. if( !NT_SUCCESS(status)) {
  318. SrvSetSmbError( WorkContext, status );
  319. SmbStatus = SmbTransStatusErrorWithoutData;
  320. goto Cleanup;
  321. }
  322. IF_SMB_DEBUG(MISC1) {
  323. SrvPrint0("SrvSmbQueryFSInformation: Using share root handle\n");
  324. }
  325. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  326. switch ( informationLevel ) {
  327. case SMB_INFO_ALLOCATION:
  328. //
  329. // Return information about the disk.
  330. //
  331. fsAllocate = (PFSALLOCATE)transaction->OutData;
  332. if ( transaction->MaxDataCount < sizeof(FSALLOCATE) ) {
  333. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  334. SrvSetSmbError( WorkContext, STATUS_BUFFER_OVERFLOW );
  335. status = STATUS_BUFFER_OVERFLOW;
  336. SmbStatus = SmbTransStatusErrorWithoutData;
  337. goto Cleanup;
  338. }
  339. //
  340. // *** The share handle is used to get the allocation
  341. // information. This is a "storage channel," and as a
  342. // result could allow people to get information to which
  343. // they are not entitled. For a B2 security rating this may
  344. // need to be changed.
  345. //
  346. status = IMPERSONATE( WorkContext );
  347. if( NT_SUCCESS( status ) ) {
  348. status = NtQueryVolumeInformationFile(
  349. fileHandle,
  350. &ioStatusBlock,
  351. &fsSizeInfo,
  352. sizeof(FILE_FS_SIZE_INFORMATION),
  353. FileFsSizeInformation
  354. );
  355. //
  356. // If the media was changed and we can come up with a new share root handle,
  357. // then we should retry the operation
  358. //
  359. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  360. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  361. if( NT_SUCCESS(status) )
  362. {
  363. status = NtQueryVolumeInformationFile(
  364. fileHandle,
  365. &ioStatusBlock,
  366. &fsSizeInfo,
  367. sizeof(FILE_FS_SIZE_INFORMATION),
  368. FileFsSizeInformation
  369. );
  370. }
  371. }
  372. REVERT();
  373. }
  374. //
  375. // Release the share root handle
  376. //
  377. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  378. if ( !NT_SUCCESS(status) ) {
  379. INTERNAL_ERROR(
  380. ERROR_LEVEL_UNEXPECTED,
  381. "SrvSmbQueryFsInformation: NtQueryVolumeInformationFile "
  382. "returned %X",
  383. status,
  384. NULL
  385. );
  386. SrvLogServiceFailure( SRV_SVC_NT_QUERY_VOL_INFO_FILE, status );
  387. SrvSetSmbError( WorkContext, status );
  388. SmbStatus = SmbTransStatusErrorWithoutData;
  389. goto Cleanup;
  390. }
  391. SmbPutAlignedUlong( &fsAllocate->idFileSystem, 0 );
  392. SmbPutAlignedUlong(
  393. &fsAllocate->cSectorUnit,
  394. fsSizeInfo.SectorsPerAllocationUnit
  395. );
  396. //
  397. // *** If .HighPart is non-zero, there is a problem, as we can
  398. // only return 32 bits for the volume size. In this case,
  399. // we return the largest value that will fit.
  400. //
  401. SmbPutAlignedUlong(
  402. &fsAllocate->cUnit,
  403. fsSizeInfo.TotalAllocationUnits.HighPart == 0 ?
  404. fsSizeInfo.TotalAllocationUnits.LowPart :
  405. 0xffffffff
  406. );
  407. SmbPutAlignedUlong(
  408. &fsAllocate->cUnitAvail,
  409. fsSizeInfo.AvailableAllocationUnits.HighPart == 0 ?
  410. fsSizeInfo.AvailableAllocationUnits.LowPart :
  411. 0xffffffff
  412. );
  413. SmbPutAlignedUshort(
  414. &fsAllocate->cbSector,
  415. (USHORT)fsSizeInfo.BytesPerSector );
  416. transaction->DataCount = sizeof(FSALLOCATE);
  417. break;
  418. case SMB_INFO_VOLUME:
  419. //
  420. // Query the volume label.
  421. //
  422. fsInfo = (PFSINFO)transaction->OutData;
  423. //
  424. // The maximum volume label length we are able to return, given
  425. // the VOLUMELABEL structure (1 byte describes length of label),
  426. // is 255 characters. Therefore, allocate a buffer large enough
  427. // to hold a label that size, and if the label is longer then we
  428. // will get STATUS_BUFFER_OVERFLOW from NtQueryVolumeInformationFile.
  429. //
  430. fsVolumeInfoLength = FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel ) +
  431. 255 * sizeof(WCHAR);
  432. fsVolumeInfo = ALLOCATE_HEAP_COLD( fsVolumeInfoLength, BlockTypeDataBuffer );
  433. if ( fsVolumeInfo == NULL ) {
  434. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  435. status = STATUS_INSUFF_SERVER_RESOURCES;
  436. SmbStatus = SmbTransStatusErrorWithoutData;
  437. goto Cleanup;
  438. }
  439. //
  440. // Get the label information.
  441. //
  442. status = NtQueryVolumeInformationFile(
  443. fileHandle,
  444. &ioStatusBlock,
  445. fsVolumeInfo,
  446. fsVolumeInfoLength,
  447. FileFsVolumeInformation
  448. );
  449. //
  450. // If the media was changed and we can come up with a new share root handle,
  451. // then we should retry the operation
  452. //
  453. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  454. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  455. if( NT_SUCCESS(status) )
  456. {
  457. status = NtQueryVolumeInformationFile(
  458. fileHandle,
  459. &ioStatusBlock,
  460. fsVolumeInfo,
  461. fsVolumeInfoLength,
  462. FileFsVolumeInformation
  463. );
  464. }
  465. }
  466. //
  467. // Release the share root handle
  468. //
  469. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  470. if ( !NT_SUCCESS(status) ) {
  471. INTERNAL_ERROR(
  472. ERROR_LEVEL_UNEXPECTED,
  473. "SrvSmbQueryFSInformation: NtQueryVolumeInformationFile "
  474. "returned %X",
  475. status,
  476. NULL
  477. );
  478. FREE_HEAP( fsVolumeInfo );
  479. SrvLogServiceFailure( SRV_SVC_NT_QUERY_VOL_INFO_FILE, status );
  480. SrvSetSmbError( WorkContext, status );
  481. SmbStatus = SmbTransStatusErrorWithoutData;
  482. goto Cleanup;
  483. }
  484. lengthVolumeLabel = fsVolumeInfo->VolumeLabelLength;
  485. //
  486. // Make sure that the client can accept enough data. The volume
  487. // label length is limited to 13 characters (8 + '.' + 3 + zero
  488. // terminator) in OS/2, so return STATUS_BUFFER_OVERFLOW if the
  489. // label is too long.
  490. //
  491. if ( !isUnicode &&
  492. !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  493. //
  494. // For a non-NT client, we truncate the volume label in case
  495. // it is longer than 11+1 characters.
  496. //
  497. if ( lengthVolumeLabel > 11 * sizeof(WCHAR) ) {
  498. lengthVolumeLabel = 11 * sizeof(WCHAR);
  499. }
  500. //
  501. // Wedge a '.' into the name if it's longer than 8 characters long
  502. //
  503. if( lengthVolumeLabel > 8 * sizeof( WCHAR ) ) {
  504. LPWSTR p = &fsVolumeInfo->VolumeLabel[11];
  505. *p = *(p-1); // VolumeLabel[11] = VolumeLabel[10]
  506. --p;
  507. *p = *(p-1); // VolumeLabel[10] = VolumeLabel[9]
  508. --p;
  509. *p = *(p-1); // VolumeLabel[9] = VolumeLabel[8]
  510. --p;
  511. *p = L'.'; // VolumeLabel[8] = '.'
  512. }
  513. }
  514. if ( (ULONG)transaction->MaxDataCount <
  515. ( sizeof(FSINFO) - sizeof(VOLUMELABEL) + sizeof( UCHAR ) +
  516. lengthVolumeLabel / (isUnicode ? 1 : sizeof(WCHAR)) ) ) {
  517. FREE_HEAP( fsVolumeInfo );
  518. SrvSetSmbError( WorkContext, STATUS_BUFFER_OVERFLOW );
  519. status = STATUS_BUFFER_OVERFLOW;
  520. SmbStatus = SmbTransStatusErrorWithoutData;
  521. goto Cleanup;
  522. }
  523. SmbPutUlong( &fsInfo->ulVsn, fsVolumeInfo->VolumeSerialNumber );
  524. //
  525. // Put the label in the SMB in Unicode or OEM, depending on what
  526. // was negotiated.
  527. //
  528. if ( isUnicode ) {
  529. RtlCopyMemory(
  530. fsInfo->vol.szVolLabel,
  531. fsVolumeInfo->VolumeLabel,
  532. lengthVolumeLabel
  533. );
  534. transaction->DataCount = sizeof(FSINFO) -
  535. sizeof(VOLUMELABEL) + lengthVolumeLabel;
  536. fsInfo->vol.cch = (UCHAR)lengthVolumeLabel;
  537. } else {
  538. ULONG i;
  539. OEM_STRING oemString;
  540. UNICODE_STRING unicodeString;
  541. if ( lengthVolumeLabel != 0 ) {
  542. oemString.Buffer = fsInfo->vol.szVolLabel;
  543. oemString.MaximumLength = 12;
  544. unicodeString.Buffer = (PWCH)fsVolumeInfo->VolumeLabel;
  545. unicodeString.Length = (USHORT) lengthVolumeLabel;
  546. unicodeString.MaximumLength = (USHORT) lengthVolumeLabel;
  547. status = RtlUnicodeStringToOemString(
  548. &oemString,
  549. &unicodeString,
  550. FALSE
  551. );
  552. ASSERT( NT_SUCCESS(status) );
  553. }
  554. fsInfo->vol.cch = (UCHAR) (lengthVolumeLabel / sizeof(WCHAR));
  555. //
  556. // Pad the end of the volume name with zeros to fill 12
  557. // characters.
  558. //
  559. for ( i = fsInfo->vol.cch + 1 ; i < 12; i++ ) {
  560. fsInfo->vol.szVolLabel[i] = '\0';
  561. }
  562. transaction->DataCount = sizeof(FSINFO);
  563. }
  564. IF_SMB_DEBUG(MISC1) {
  565. SrvPrint2( "volume label length is %d and label is %s\n",
  566. fsInfo->vol.cch, fsInfo->vol.szVolLabel );
  567. }
  568. FREE_HEAP( fsVolumeInfo );
  569. break;
  570. case SMB_QUERY_FS_VOLUME_INFO:
  571. case SMB_QUERY_FS_DEVICE_INFO:
  572. case SMB_QUERY_FS_ATTRIBUTE_INFO:
  573. //
  574. // These are NT infolevels. We always return unicode.
  575. // Except for the fact that NEXUS on WFW calls through here and is
  576. // not unicode (isaache)
  577. //
  578. // ASSERT( isUnicode );
  579. status = IMPERSONATE( WorkContext );
  580. if( NT_SUCCESS( status ) ) {
  581. status = NtQueryVolumeInformationFile(
  582. fileHandle,
  583. &ioStatusBlock,
  584. transaction->OutData,
  585. transaction->MaxDataCount,
  586. MAP_SMB_INFO_TYPE_TO_NT(
  587. QueryVolumeInformation,
  588. informationLevel
  589. )
  590. );
  591. //
  592. // If the media was changed and we can come up with a new share root handle,
  593. // then we should retry the operation
  594. //
  595. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  596. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  597. if( NT_SUCCESS(status) )
  598. {
  599. status = NtQueryVolumeInformationFile(
  600. fileHandle,
  601. &ioStatusBlock,
  602. transaction->OutData,
  603. transaction->MaxDataCount,
  604. MAP_SMB_INFO_TYPE_TO_NT(
  605. QueryVolumeInformation,
  606. informationLevel
  607. )
  608. );
  609. }
  610. }
  611. REVERT();
  612. }
  613. //
  614. // Release the share root handle
  615. //
  616. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  617. if ( NT_SUCCESS( status ) ) {
  618. //
  619. // We need to return FAT to the client if the host volume is really
  620. // FAT32
  621. //
  622. if( informationLevel == SMB_QUERY_FS_ATTRIBUTE_INFO &&
  623. ioStatusBlock.Information > sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) ) {
  624. PFILE_FS_ATTRIBUTE_INFORMATION attrInfo =
  625. (PFILE_FS_ATTRIBUTE_INFORMATION)(transaction->OutData);
  626. if( attrInfo->FileSystemNameLength > 3*sizeof(WCHAR) &&
  627. attrInfo->FileSystemName[0] == L'F' &&
  628. attrInfo->FileSystemName[1] == L'A' &&
  629. attrInfo->FileSystemName[2] == L'T' ) {
  630. ioStatusBlock.Information =
  631. ioStatusBlock.Information -
  632. (attrInfo->FileSystemNameLength - 3*sizeof(WCHAR) );
  633. attrInfo->FileSystemNameLength = 3 * sizeof(WCHAR);
  634. attrInfo->FileSystemName[3] = UNICODE_NULL;
  635. }
  636. }
  637. transaction->DataCount = (ULONG)ioStatusBlock.Information;
  638. } else {
  639. SrvSetSmbError( WorkContext, status );
  640. SmbStatus = SmbTransStatusErrorWithoutData;
  641. goto Cleanup;
  642. }
  643. break;
  644. case SMB_QUERY_FS_SIZE_INFO:
  645. //
  646. // These are NT infolevels. We always return unicode.
  647. // Except for the fact that NEXUS on WFW calls through here and is
  648. // not unicode (isaache)
  649. //
  650. // ASSERT( isUnicode );
  651. status = IMPERSONATE( WorkContext );
  652. if( NT_SUCCESS( status ) ) {
  653. status = NtQueryVolumeInformationFile(
  654. fileHandle,
  655. &ioStatusBlock,
  656. transaction->OutData,
  657. transaction->MaxDataCount,
  658. MAP_SMB_INFO_TYPE_TO_NT(
  659. QueryVolumeInformation,
  660. informationLevel
  661. )
  662. );
  663. //
  664. // If the media was changed and we can come up with a new share root handle,
  665. // then we should retry the operation
  666. //
  667. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  668. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  669. if( NT_SUCCESS(status) )
  670. {
  671. status = NtQueryVolumeInformationFile(
  672. fileHandle,
  673. &ioStatusBlock,
  674. transaction->OutData,
  675. transaction->MaxDataCount,
  676. MAP_SMB_INFO_TYPE_TO_NT(
  677. QueryVolumeInformation,
  678. informationLevel
  679. )
  680. );
  681. }
  682. }
  683. REVERT();
  684. }
  685. //
  686. // Release the share root handle
  687. //
  688. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  689. if ( NT_SUCCESS( status ) ) {
  690. transaction->DataCount = (ULONG)ioStatusBlock.Information;
  691. } else {
  692. SrvSetSmbError( WorkContext, status );
  693. SmbStatus = SmbTransStatusErrorWithoutData;
  694. goto Cleanup;
  695. }
  696. break;
  697. default:
  698. //
  699. // An invalid information level was passed.
  700. //
  701. SrvSetSmbError( WorkContext, STATUS_OS2_INVALID_LEVEL );
  702. status = STATUS_OS2_INVALID_LEVEL;
  703. SmbStatus = SmbTransStatusErrorWithoutData;
  704. goto Cleanup;
  705. }
  706. } else {
  707. informationLevel -= SMB_INFO_PASSTHROUGH;
  708. status = IoCheckQuerySetVolumeInformation( informationLevel,
  709. transaction->MaxDataCount,
  710. FALSE
  711. );
  712. if( NT_SUCCESS( status ) ) {
  713. status = IMPERSONATE( WorkContext );
  714. if( NT_SUCCESS( status ) ) {
  715. status = NtQueryVolumeInformationFile(
  716. fileHandle,
  717. &ioStatusBlock,
  718. transaction->OutData,
  719. transaction->MaxDataCount,
  720. informationLevel
  721. );
  722. //
  723. // If the media was changed and we can come up with a new share root handle,
  724. // then we should retry the operation
  725. //
  726. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  727. status = SrvSnapGetRootHandle( WorkContext, &fileHandle );
  728. if( NT_SUCCESS(status) )
  729. {
  730. status = NtQueryVolumeInformationFile(
  731. fileHandle,
  732. &ioStatusBlock,
  733. transaction->OutData,
  734. transaction->MaxDataCount,
  735. informationLevel
  736. );
  737. }
  738. }
  739. REVERT();
  740. }
  741. }
  742. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  743. if ( NT_SUCCESS( status ) ) {
  744. transaction->DataCount = (ULONG)ioStatusBlock.Information;
  745. } else {
  746. SrvSetSmbError( WorkContext, status );
  747. SmbStatus = SmbTransStatusErrorWithoutData;
  748. goto Cleanup;
  749. }
  750. }
  751. transaction->SetupCount = 0;
  752. transaction->ParameterCount = 0;
  753. SmbStatus = SmbTransStatusSuccess;
  754. Cleanup:
  755. SrvWmiEndContext(WorkContext);
  756. return SmbStatus;
  757. } // SrvSmbQueryFsInformation
  758. SMB_TRANS_STATUS
  759. SrvSmbSetFsInformation (
  760. IN OUT PWORK_CONTEXT WorkContext
  761. )
  762. /*++
  763. Routine Description:
  764. Processes the Set FS Information request. This request arrives
  765. in a Transaction2 SMB.
  766. Arguments:
  767. WorkContext - Supplies the address of a Work Context Block
  768. describing the current request. See smbtypes.h for a more
  769. complete description of the valid fields.
  770. Return Value:
  771. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  772. whether data should be returned to the client. See smbtypes.h
  773. for a more complete description.
  774. --*/
  775. {
  776. SMB_TRANS_STATUS transactionStatus = SmbTransStatusInProgress;
  777. PREQ_SET_FS_INFORMATION request;
  778. NTSTATUS status = STATUS_SUCCESS;
  779. IO_STATUS_BLOCK ioStatusBlock;
  780. PTRANSACTION transaction;
  781. USHORT informationLevel;
  782. PSESSION session;
  783. PTREE_CONNECT treeConnect;
  784. PRFCB rfcb;
  785. PAGED_CODE( );
  786. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  787. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SET_FS_INFORMATION;
  788. SrvWmiStartContext(WorkContext);
  789. transaction = WorkContext->Parameters.Transaction;
  790. IF_SMB_DEBUG(MISC1) {
  791. SrvPrint1( "Set FS Information entered; transaction 0x%p\n",
  792. transaction );
  793. }
  794. status = SrvVerifyUidAndTid(
  795. WorkContext,
  796. &session,
  797. &treeConnect,
  798. ShareTypeDisk
  799. );
  800. if( !NT_SUCCESS( status ) ) {
  801. goto out;
  802. }
  803. //
  804. // Verify that enough parameter bytes were sent and that we're allowed
  805. // to return enough parameter bytes. Set FS information has no
  806. // response parameters.
  807. //
  808. request = (PREQ_SET_FS_INFORMATION)transaction->InParameters;
  809. if ( (transaction->ParameterCount < sizeof(REQ_SET_FS_INFORMATION)) ) {
  810. //
  811. // Not enough parameter bytes were sent.
  812. //
  813. IF_SMB_DEBUG(ERRORS) {
  814. SrvPrint2( "SrvSmbSetFSInformation: bad parameter byte "
  815. "counts: %ld %ld\n",
  816. transaction->ParameterCount,
  817. transaction->MaxParameterCount );
  818. }
  819. status = STATUS_INVALID_SMB;
  820. SrvLogInvalidSmb( WorkContext );
  821. goto out;
  822. }
  823. //
  824. // Confirm that the information level is legitimate.
  825. //
  826. informationLevel = SmbGetUshort( &request->InformationLevel );
  827. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  828. status = STATUS_NOT_SUPPORTED;
  829. goto out;
  830. }
  831. informationLevel -= SMB_INFO_PASSTHROUGH;
  832. //
  833. // Make sure the client is allowed to do this, if we have an Admin share
  834. //
  835. status = SrvIsAllowedOnAdminShare( WorkContext, WorkContext->TreeConnect->Share );
  836. if( !NT_SUCCESS( status ) ) {
  837. goto out;
  838. }
  839. //
  840. // Verify the FID. If verified, the RFCB block is referenced
  841. // and its addresses is stored in the WorkContext block, and the
  842. // RFCB address is returned.
  843. //
  844. rfcb = SrvVerifyFid(
  845. WorkContext,
  846. SmbGetUshort( &request->Fid ),
  847. TRUE,
  848. NULL, // don't serialize with raw write
  849. &status
  850. );
  851. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  852. IF_DEBUG(ERRORS) {
  853. SrvPrint2(
  854. "SrvSmbSetFsInformation: Status %X on FID: 0x%lx\n",
  855. status,
  856. SmbGetUshort( &request->Fid )
  857. );
  858. }
  859. goto out;
  860. }
  861. status = IoCheckQuerySetVolumeInformation(
  862. informationLevel,
  863. transaction->DataCount,
  864. TRUE
  865. );
  866. if( NT_SUCCESS( status ) ) {
  867. status = IMPERSONATE( WorkContext );
  868. if( NT_SUCCESS( status ) ) {
  869. status = NtSetVolumeInformationFile(
  870. rfcb->Lfcb->FileHandle,
  871. &ioStatusBlock,
  872. transaction->InData,
  873. transaction->DataCount,
  874. informationLevel
  875. );
  876. REVERT();
  877. }
  878. }
  879. out:
  880. if ( !NT_SUCCESS( status ) ) {
  881. SrvSetSmbError( WorkContext, status );
  882. transactionStatus = SmbTransStatusErrorWithoutData;
  883. } else {
  884. transactionStatus = SmbTransStatusSuccess;
  885. }
  886. transaction->SetupCount = 0;
  887. transaction->ParameterCount = 0;
  888. transaction->DataCount = 0;
  889. SrvWmiEndContext(WorkContext);
  890. return transactionStatus;
  891. } // SrvSmbSetFsInformation
  892. SMB_PROCESSOR_RETURN_TYPE
  893. SrvSmbQueryInformationDisk (
  894. SMB_PROCESSOR_PARAMETERS
  895. )
  896. /*++
  897. Routine Description:
  898. This routine processes the Query Information Disk SMB.
  899. Arguments:
  900. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  901. of the parameters to SMB processor routines.
  902. Return Value:
  903. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  904. --*/
  905. {
  906. PREQ_QUERY_INFORMATION_DISK request;
  907. PRESP_QUERY_INFORMATION_DISK response;
  908. NTSTATUS status = STATUS_SUCCESS;
  909. SMB_STATUS SmbStatus = SmbStatusInProgress;
  910. IO_STATUS_BLOCK ioStatusBlock;
  911. FILE_FS_SIZE_INFORMATION fsSizeInfo;
  912. PSESSION session;
  913. PTREE_CONNECT treeConnect;
  914. USHORT totalUnits, freeUnits;
  915. ULONG sectorsPerUnit, bytesPerSector;
  916. LARGE_INTEGER result;
  917. BOOLEAN highpart;
  918. ULONG searchword;
  919. CCHAR highbit, extrabits;
  920. BOOLEAN isDos;
  921. PAGED_CODE( );
  922. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  923. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_INFORMATION_DISK;
  924. SrvWmiStartContext(WorkContext);
  925. IF_SMB_DEBUG(MISC1) {
  926. SrvPrint2( "Query Information Disk request header at 0x%p, response header at 0x%p\n",
  927. WorkContext->RequestHeader,
  928. WorkContext->ResponseHeader );
  929. SrvPrint2( "Query Information Disk request params at 0x%p, response params%p\n",
  930. WorkContext->RequestParameters,
  931. WorkContext->ResponseParameters );
  932. }
  933. request = (PREQ_QUERY_INFORMATION_DISK)WorkContext->RequestParameters;
  934. response = (PRESP_QUERY_INFORMATION_DISK)WorkContext->ResponseParameters;
  935. //
  936. // If a session block has not already been assigned to the current
  937. // work context , verify the UID. If verified, the address of the
  938. // session block corresponding to this user is stored in the WorkContext
  939. // block and the session block is referenced.
  940. //
  941. // Find tree connect corresponding to given TID if a tree connect
  942. // pointer has not already been put in the WorkContext block by an
  943. // AndX command.
  944. //
  945. status = SrvVerifyUidAndTid(
  946. WorkContext,
  947. &session,
  948. &treeConnect,
  949. ShareTypeDisk
  950. );
  951. if ( !NT_SUCCESS(status) ) {
  952. IF_DEBUG(SMB_ERRORS) {
  953. SrvPrint0( "SrvSmbQueryInformationDisk: Invalid UID or TID\n" );
  954. }
  955. SrvSetSmbError( WorkContext, status );
  956. SmbStatus = SmbStatusSendResponse;
  957. goto Cleanup;
  958. }
  959. if( session->IsSessionExpired )
  960. {
  961. status = SESSION_EXPIRED_STATUS_CODE;
  962. SrvSetSmbError( WorkContext, status );
  963. SmbStatus = SmbStatusSendResponse;
  964. goto Cleanup;
  965. }
  966. //
  967. // Make sure the client is allowed to do this, if we have an Admin share
  968. //
  969. status = SrvIsAllowedOnAdminShare( WorkContext, treeConnect->Share );
  970. if( !NT_SUCCESS( status ) ) {
  971. SrvSetSmbError( WorkContext, status );
  972. SmbStatus = SmbStatusSendResponse;
  973. goto Cleanup;
  974. }
  975. //
  976. // Get the Share root handle.
  977. //
  978. status = SrvGetShareRootHandle( treeConnect->Share );
  979. if ( !NT_SUCCESS(status) ) {
  980. IF_DEBUG(ERRORS) {
  981. SrvPrint1( "SrvSmbQueryInformationDisk: SrvGetShareRootHandle failed %x.\n",
  982. status );
  983. }
  984. SrvSetSmbError( WorkContext, status );
  985. SmbStatus = SmbStatusSendResponse;
  986. goto Cleanup;
  987. }
  988. //
  989. // *** The share handle is used to get the allocation information.
  990. // This is a "storage channel," and as a result could allow
  991. // people to get information to which they are not entitled.
  992. // For a B2 security rating this may need to be changed.
  993. //
  994. status = IMPERSONATE( WorkContext );
  995. if( NT_SUCCESS( status ) ) {
  996. HANDLE RootHandle;
  997. status = SrvSnapGetRootHandle( WorkContext, &RootHandle );
  998. if( NT_SUCCESS(status) )
  999. {
  1000. status = NtQueryVolumeInformationFile(
  1001. RootHandle,
  1002. &ioStatusBlock,
  1003. &fsSizeInfo,
  1004. sizeof(FILE_FS_SIZE_INFORMATION),
  1005. FileFsSizeInformation
  1006. );
  1007. //
  1008. // If the media was changed and we can come up with a new share root handle,
  1009. // then we should retry the operation
  1010. //
  1011. if( SrvRetryDueToDismount( WorkContext->TreeConnect->Share, status ) ) {
  1012. status = SrvSnapGetRootHandle( WorkContext, &RootHandle );
  1013. if( NT_SUCCESS(status) )
  1014. {
  1015. status = NtQueryVolumeInformationFile(
  1016. RootHandle,
  1017. &ioStatusBlock,
  1018. &fsSizeInfo,
  1019. sizeof(FILE_FS_SIZE_INFORMATION),
  1020. FileFsSizeInformation
  1021. );
  1022. }
  1023. }
  1024. }
  1025. REVERT();
  1026. }
  1027. //
  1028. // Release the share root handle
  1029. //
  1030. SrvReleaseShareRootHandle( treeConnect->Share );
  1031. if ( !NT_SUCCESS(status) ) {
  1032. INTERNAL_ERROR(
  1033. ERROR_LEVEL_UNEXPECTED,
  1034. "SrvSmbQueryInformationDisk: NtQueryVolumeInformationFile"
  1035. "returned %X",
  1036. status,
  1037. NULL
  1038. );
  1039. SrvLogServiceFailure( SRV_SVC_NT_SET_VOL_INFO_FILE, status );
  1040. SrvSetSmbError( WorkContext, status );
  1041. SmbStatus = SmbStatusSendResponse;
  1042. goto Cleanup;
  1043. }
  1044. //
  1045. // *** Problem.
  1046. //
  1047. // This SMB only return 16 bits of information for each field, but we
  1048. // may need to return large numbers. In particular TotalAllocationUnits
  1049. // is commonly > 64K.
  1050. //
  1051. // Fortunately, it turns out the all the client cares about is the total
  1052. // disk size, in bytes, and the free space, in bytes. So - if one number
  1053. // is too big adjust it and adjust the other numbers so that the totals
  1054. // come out the same.
  1055. //
  1056. // If after all adjustment, the number are still too high, return the
  1057. // largest possible value for TotalUnit or FreeUnits (i.e. 0xFFFF).
  1058. //
  1059. // A caveat here is that some DOS apps (like the command interpreter!)
  1060. // assume that the cluster size (bytes per sector times sectors per
  1061. // cluster) will fit in 16 bits, and will calculate bogus geometry if
  1062. // it doesn't. So the first thing we do is ensure that the real
  1063. // cluster size is less than 0x10000, if the client is a DOS client.
  1064. // This may make the TotalUnits or FreeUnits counts too big, so we'll
  1065. // have to round them down, but that's life.
  1066. //
  1067. // Since we use shifts to adjust the numbers it is possible to lose
  1068. // 1 bits when we shift a number to the right. We don't care, we're
  1069. // doing our best to fix a broken protocol. NT clients will use
  1070. // QueryFSAttribute and will get the correct answer.
  1071. //
  1072. //
  1073. // If this is a DOS client, make the cluster size < 0x10000.
  1074. //
  1075. isDos = IS_DOS_DIALECT( WorkContext->Connection->SmbDialect );
  1076. sectorsPerUnit = fsSizeInfo.SectorsPerAllocationUnit;
  1077. bytesPerSector = fsSizeInfo.BytesPerSector;
  1078. if ( isDos ) {
  1079. while ( (sectorsPerUnit * bytesPerSector) > 0xFFFF ) {
  1080. if ( sectorsPerUnit >= 2 ) {
  1081. sectorsPerUnit /= 2;
  1082. } else {
  1083. bytesPerSector /= 2;
  1084. }
  1085. fsSizeInfo.TotalAllocationUnits.QuadPart *= 2;
  1086. fsSizeInfo.AvailableAllocationUnits.QuadPart *= 2;
  1087. }
  1088. }
  1089. //
  1090. // Calculate how much the total cluster count needs to be shifted in
  1091. // order to fit in a word.
  1092. //
  1093. if ( fsSizeInfo.TotalAllocationUnits.HighPart != 0 ) {
  1094. highpart = TRUE;
  1095. searchword = fsSizeInfo.TotalAllocationUnits.HighPart;
  1096. } else {
  1097. highpart = FALSE;
  1098. searchword = fsSizeInfo.TotalAllocationUnits.LowPart;
  1099. }
  1100. highbit = 0;
  1101. while ( searchword != 0 ) {
  1102. highbit++;
  1103. searchword /= 2;
  1104. }
  1105. if ( highpart ) {
  1106. highbit += 32;
  1107. } else {
  1108. if ( highbit < 16) {
  1109. highbit = 0;
  1110. } else {
  1111. highbit -= 16;
  1112. }
  1113. }
  1114. if ( highbit > 0 ) {
  1115. //
  1116. // Attempt to adjust the other values to absorb the excess bits.
  1117. // If this is a DOS client, don't let the cluster size get
  1118. // bigger than 0xFFFF.
  1119. //
  1120. extrabits = highbit;
  1121. if ( isDos ) {
  1122. while ( (highbit > 0) &&
  1123. ((sectorsPerUnit*bytesPerSector) < 0x8000) ) {
  1124. sectorsPerUnit *= 2;
  1125. highbit--;
  1126. }
  1127. } else {
  1128. while ( (highbit > 0) && (sectorsPerUnit < 0x8000) ) {
  1129. sectorsPerUnit *= 2;
  1130. highbit--;
  1131. }
  1132. while ( (highbit > 0) && (bytesPerSector < 0x8000) ) {
  1133. bytesPerSector *= 2;
  1134. highbit--;
  1135. }
  1136. }
  1137. //
  1138. // Adjust the total and free unit counts.
  1139. //
  1140. if ( highbit > 0 ) {
  1141. //
  1142. // There is no way to get the information to fit. Use the
  1143. // maximum possible value.
  1144. //
  1145. totalUnits = 0xFFFF;
  1146. } else {
  1147. result.QuadPart = fsSizeInfo.TotalAllocationUnits.QuadPart >> extrabits;
  1148. ASSERT( result.HighPart == 0 );
  1149. ASSERT( result.LowPart < 0x10000 );
  1150. totalUnits = (USHORT)result.LowPart;
  1151. }
  1152. result.QuadPart = fsSizeInfo.AvailableAllocationUnits.QuadPart >>
  1153. (CCHAR)(extrabits - highbit);
  1154. if ( result.HighPart != 0 || result.LowPart > 0xFFFF ) {
  1155. freeUnits = 0xFFFF;
  1156. } else {
  1157. freeUnits = (USHORT)result.LowPart;
  1158. }
  1159. } else {
  1160. totalUnits = (USHORT)fsSizeInfo.TotalAllocationUnits.LowPart;
  1161. freeUnits = (USHORT)fsSizeInfo.AvailableAllocationUnits.LowPart;
  1162. }
  1163. //
  1164. // Build the response SMB.
  1165. //
  1166. response->WordCount = 5;
  1167. SmbPutUshort( &response->TotalUnits, totalUnits );
  1168. SmbPutUshort( &response->BlocksPerUnit, (USHORT)sectorsPerUnit );
  1169. SmbPutUshort( &response->BlockSize, (USHORT)bytesPerSector );
  1170. SmbPutUshort( &response->FreeUnits, freeUnits );
  1171. SmbPutUshort( &response->Reserved, 0 );
  1172. SmbPutUshort( &response->ByteCount, 0 );
  1173. WorkContext->ResponseParameters = NEXT_LOCATION(
  1174. response,
  1175. RESP_QUERY_INFORMATION_DISK,
  1176. 0
  1177. );
  1178. SmbStatus = SmbStatusSendResponse;
  1179. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbQueryInformationDisk complete.\n" );
  1180. Cleanup:
  1181. SrvWmiEndContext(WorkContext);
  1182. return SmbStatus;
  1183. } // SrvSmbQueryInformationDisk
  1184. SMB_PROCESSOR_RETURN_TYPE
  1185. SrvSmbNtCancel (
  1186. SMB_PROCESSOR_PARAMETERS
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. Processes an Nt Cancel SMB.
  1191. Arguments:
  1192. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  1193. of the parameters to SMB processor routines.
  1194. Return Value:
  1195. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  1196. --*/
  1197. {
  1198. NTSTATUS status = STATUS_SUCCESS;
  1199. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1200. PSESSION session;
  1201. PTREE_CONNECT treeConnect;
  1202. PCONNECTION connection;
  1203. USHORT targetUid, targetPid, targetTid, targetMid;
  1204. PLIST_ENTRY listHead;
  1205. PLIST_ENTRY listEntry;
  1206. PWORK_CONTEXT workContext;
  1207. PSMB_HEADER header;
  1208. BOOLEAN match;
  1209. KIRQL oldIrql;
  1210. PREQ_NT_CANCEL request;
  1211. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1212. WorkContext->PreviousSMB = EVENT_TYPE_SMB_NT_CANCEL;
  1213. SrvWmiStartContext(WorkContext);
  1214. request = (PREQ_NT_CANCEL)WorkContext->RequestParameters;
  1215. //
  1216. // The word count has already been checked. Now make sure that
  1217. // the byte count is zero.
  1218. //
  1219. if ( SmbGetUshort( &request->ByteCount) != 0 ) {
  1220. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1221. status = STATUS_INVALID_SMB;
  1222. SmbStatus = SmbStatusSendResponse;
  1223. goto Cleanup;
  1224. }
  1225. //
  1226. // If a session block has not already been assigned to the current
  1227. // work context , verify the UID. If verified, the address of the
  1228. // session block corresponding to this user is stored in the WorkContext
  1229. // block and the session block is referenced.
  1230. //
  1231. // Find tree connect corresponding to given TID if a tree connect
  1232. // pointer has not already been put in the WorkContext block by an
  1233. // AndX command.
  1234. //
  1235. status = SrvVerifyUidAndTid(
  1236. WorkContext,
  1237. &session,
  1238. &treeConnect,
  1239. ShareTypeWild
  1240. );
  1241. if ( !NT_SUCCESS(status) ) {
  1242. IF_DEBUG(SMB_ERRORS) {
  1243. SrvPrint0( "SrvSmbNtCancel: Invalid UID or TID\n" );
  1244. }
  1245. SrvSetSmbError( WorkContext, status );
  1246. SmbStatus = SmbStatusSendResponse;
  1247. goto Cleanup;
  1248. }
  1249. //
  1250. // Check the work in-progress list to see if this work item is
  1251. // cancellable.
  1252. //
  1253. targetUid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid );
  1254. targetPid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1255. targetTid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid );
  1256. targetMid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Mid );
  1257. match = FALSE;
  1258. connection = WorkContext->Connection;
  1259. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  1260. listHead = &connection->InProgressWorkItemList;
  1261. listEntry = listHead;
  1262. while ( listEntry->Flink != listHead ) {
  1263. listEntry = listEntry->Flink;
  1264. workContext = CONTAINING_RECORD(
  1265. listEntry,
  1266. WORK_CONTEXT,
  1267. InProgressListEntry
  1268. );
  1269. header = workContext->RequestHeader;
  1270. //
  1271. // Some workitems in the inprogressworkitemlist are added
  1272. // during a receive indication and the requestheader field
  1273. // has not been set yet. We can probably set it at that time
  1274. // but this seems to be the safest fix.
  1275. //
  1276. // We have to check whether the workitem ref count is zero or
  1277. // not since we dereference it before removing it from the
  1278. // InProgressWorkItemList queue. This prevents the workitem
  1279. // from being cleaned up twice.
  1280. //
  1281. // We also need to check the processing count of the workitem.
  1282. // Work items being used for actual smb requests will have
  1283. // a processing count of at least 1. This will prevent us
  1284. // from touching oplock breaks and pending tdi receives.
  1285. //
  1286. ACQUIRE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1287. if ( (workContext->BlockHeader.ReferenceCount != 0) &&
  1288. (workContext->ProcessingCount != 0) &&
  1289. header != NULL &&
  1290. header->Command != SMB_COM_NT_CANCEL &&
  1291. SmbGetAlignedUshort( &header->Mid ) == targetMid &&
  1292. SmbGetAlignedUshort( &header->Pid ) == targetPid &&
  1293. SmbGetAlignedUshort( &header->Tid ) == targetTid &&
  1294. SmbGetAlignedUshort( &header->Uid ) == targetUid ) {
  1295. match = TRUE;
  1296. break;
  1297. }
  1298. RELEASE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1299. }
  1300. if ( match ) {
  1301. //
  1302. // Reference the work item, so that it cannot get used to process
  1303. // a new SMB while we are trying to cancel the old one.
  1304. //
  1305. SrvReferenceWorkItem( workContext );
  1306. RELEASE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1307. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1308. (VOID)IoCancelIrp( workContext->Irp );
  1309. SrvDereferenceWorkItem( workContext );
  1310. } else {
  1311. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1312. }
  1313. //
  1314. // Done. Do not send a response
  1315. //
  1316. SmbStatus = SmbStatusNoResponse;
  1317. Cleanup:
  1318. SrvWmiEndContext(WorkContext);
  1319. return SmbStatus;
  1320. } // SrvSmbNtCancel
  1321. SMB_TRANS_STATUS
  1322. SrvSmbSetSecurityDescriptor (
  1323. IN OUT PWORK_CONTEXT WorkContext
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. Processes the Set Security Descriptor request. This request arrives
  1328. in a Transaction2 SMB.
  1329. Arguments:
  1330. WorkContext - Supplies the address of a Work Context Block
  1331. describing the current request. See smbtypes.h for a more
  1332. complete description of the valid fields.
  1333. Return Value:
  1334. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  1335. whether data should be returned to the client. See smbtypes.h
  1336. for a more complete description.
  1337. --*/
  1338. {
  1339. PREQ_SET_SECURITY_DESCRIPTOR request;
  1340. NTSTATUS status;
  1341. PTRANSACTION transaction;
  1342. PRFCB rfcb;
  1343. SECURITY_INFORMATION securityInformation;
  1344. PAGED_CODE( );
  1345. transaction = WorkContext->Parameters.Transaction;
  1346. IF_SMB_DEBUG(QUERY_SET1) {
  1347. SrvPrint1( "Set Security Descriptor entered; transaction 0x%p\n",
  1348. transaction );
  1349. }
  1350. request = (PREQ_SET_SECURITY_DESCRIPTOR)transaction->InParameters;
  1351. //
  1352. // Verify that enough setup bytes were sent.
  1353. //
  1354. if ( transaction->ParameterCount < sizeof(REQ_SET_SECURITY_DESCRIPTOR ) ) {
  1355. //
  1356. // Not enough parameter bytes were sent.
  1357. //
  1358. IF_DEBUG(SMB_ERRORS) {
  1359. SrvPrint1( "SrvSmbSetSecurityInformation: bad setup byte count: "
  1360. "%ld\n",
  1361. transaction->ParameterCount );
  1362. }
  1363. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1364. return SmbTransStatusErrorWithoutData;
  1365. }
  1366. //
  1367. // Verify the FID. If verified, the RFCB block is referenced
  1368. // and its addresses is stored in the WorkContext block, and the
  1369. // RFCB address is returned.
  1370. //
  1371. rfcb = SrvVerifyFid(
  1372. WorkContext,
  1373. SmbGetUshort( &request->Fid ),
  1374. TRUE,
  1375. NULL, // don't serialize with raw write
  1376. &status
  1377. );
  1378. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1379. //
  1380. // Invalid file ID or write behind error. Reject the request.
  1381. //
  1382. IF_DEBUG(ERRORS) {
  1383. SrvPrint2(
  1384. "SrvSmbSetFileInformation: Status %X on FID: 0x%lx\n",
  1385. status,
  1386. SmbGetUshort( &request->Fid )
  1387. );
  1388. }
  1389. SrvSetSmbError( WorkContext, status );
  1390. return SmbTransStatusErrorWithoutData;
  1391. }
  1392. //
  1393. // First we'll validate that the security descriptor isn't bogus.
  1394. // This needs to be done here because NtSetSecurityObject has no
  1395. // idea what the buffer size is.
  1396. //
  1397. if( !RtlValidRelativeSecurityDescriptor( transaction->InData,
  1398. transaction->DataCount,
  1399. 0 )) {
  1400. //
  1401. // We were passed a bogus security descriptor to set. Bounce the
  1402. // request as an invalid SMB.
  1403. //
  1404. SrvSetSmbError( WorkContext, STATUS_INVALID_SECURITY_DESCR );
  1405. return SmbTransStatusErrorWithoutData;
  1406. }
  1407. securityInformation = SmbGetUlong( &request->SecurityInformation );
  1408. //
  1409. // Make sure the caller is allowed to set security information on this object
  1410. //
  1411. status = IoCheckFunctionAccess( rfcb->GrantedAccess,
  1412. IRP_MJ_SET_SECURITY,
  1413. 0,
  1414. 0,
  1415. &securityInformation,
  1416. NULL
  1417. );
  1418. if( NT_SUCCESS( status ) ) {
  1419. //
  1420. // Attempt to set the security descriptor. We need to be in the
  1421. // the user context to do this, in case the security information
  1422. // specifies change ownership.
  1423. //
  1424. status = IMPERSONATE( WorkContext );
  1425. if( NT_SUCCESS( status ) ) {
  1426. status = NtSetSecurityObject(
  1427. rfcb->Lfcb->FileHandle,
  1428. securityInformation,
  1429. transaction->InData
  1430. );
  1431. REVERT();
  1432. }
  1433. }
  1434. //
  1435. // If an error occurred, return an appropriate response.
  1436. //
  1437. if ( !NT_SUCCESS(status) ) {
  1438. SrvSetSmbError( WorkContext, status );
  1439. return SmbTransStatusErrorWithoutData;
  1440. }
  1441. //
  1442. // We probably shouldn't cache this file descriptor on close, since
  1443. // the security setting changed.
  1444. //
  1445. rfcb->IsCacheable = FALSE;
  1446. transaction->ParameterCount = 0;
  1447. transaction->DataCount = 0;
  1448. return SmbTransStatusSuccess;
  1449. } // SrvSmbSetSecurityDescriptor
  1450. SMB_TRANS_STATUS
  1451. SrvSmbQuerySecurityDescriptor (
  1452. IN OUT PWORK_CONTEXT WorkContext
  1453. )
  1454. /*++
  1455. Routine Description:
  1456. Processes the Query Security Descriptor request. This request arrives
  1457. in a Transaction2 SMB.
  1458. Arguments:
  1459. WorkContext - Supplies the address of a Work Context Block
  1460. describing the current request. See smbtypes.h for a more
  1461. complete description of the valid fields.
  1462. Return Value:
  1463. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  1464. whether data should be returned to the client. See smbtypes.h
  1465. for a more complete description.
  1466. --*/
  1467. {
  1468. PREQ_QUERY_SECURITY_DESCRIPTOR request;
  1469. PRESP_QUERY_SECURITY_DESCRIPTOR response;
  1470. NTSTATUS status;
  1471. PTRANSACTION transaction;
  1472. PRFCB rfcb;
  1473. ULONG lengthNeeded;
  1474. SECURITY_INFORMATION securityInformation;
  1475. PAGED_CODE( );
  1476. transaction = WorkContext->Parameters.Transaction;
  1477. IF_SMB_DEBUG(QUERY_SET1) {
  1478. SrvPrint1( "Query Security Descriptor entered; transaction 0x%p\n",
  1479. transaction );
  1480. }
  1481. request = (PREQ_QUERY_SECURITY_DESCRIPTOR)transaction->InParameters;
  1482. response = (PRESP_QUERY_SECURITY_DESCRIPTOR)transaction->OutParameters;
  1483. //
  1484. // Verify that enough setup bytes were sent.
  1485. //
  1486. if ( transaction->ParameterCount < sizeof(REQ_QUERY_SECURITY_DESCRIPTOR ) ||
  1487. transaction->MaxParameterCount <
  1488. sizeof( RESP_QUERY_SECURITY_DESCRIPTOR ) ) {
  1489. //
  1490. // Not enough parameter bytes were sent.
  1491. //
  1492. IF_DEBUG(SMB_ERRORS) {
  1493. SrvPrint2( "SrvSmbQuerySecurityInformation: bad parameter byte or "
  1494. "return parameter count: %ld %ld\n",
  1495. transaction->ParameterCount,
  1496. transaction->MaxParameterCount );
  1497. }
  1498. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1499. return SmbTransStatusErrorWithoutData;
  1500. }
  1501. //
  1502. // Verify the FID. If verified, the RFCB block is referenced
  1503. // and its addresses is stored in the WorkContext block, and the
  1504. // RFCB address is returned.
  1505. //
  1506. rfcb = SrvVerifyFid(
  1507. WorkContext,
  1508. SmbGetUshort( &request->Fid ),
  1509. TRUE,
  1510. NULL, // don't serialize with raw write
  1511. &status
  1512. );
  1513. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1514. //
  1515. // Invalid file ID or write behind error. Reject the request.
  1516. //
  1517. IF_DEBUG(ERRORS) {
  1518. SrvPrint2(
  1519. "SrvSmbSetFileInformation: Status %X on FID: 0x%lx\n",
  1520. status,
  1521. SmbGetUshort( &request->Fid )
  1522. );
  1523. }
  1524. SrvSetSmbError( WorkContext, status );
  1525. return SmbTransStatusErrorWithoutData;
  1526. }
  1527. securityInformation = SmbGetUlong( &request->SecurityInformation ),
  1528. //
  1529. // Make sure the caller is allowed to query security information on this object
  1530. //
  1531. status = IoCheckFunctionAccess( rfcb->GrantedAccess,
  1532. IRP_MJ_QUERY_SECURITY,
  1533. 0,
  1534. 0,
  1535. &securityInformation,
  1536. NULL
  1537. );
  1538. if( !NT_SUCCESS( status ) ) {
  1539. SrvSetSmbError( WorkContext, status );
  1540. return SmbTransStatusErrorWithoutData;
  1541. }
  1542. //
  1543. // Attempt to query the security descriptor
  1544. //
  1545. status = NtQuerySecurityObject(
  1546. rfcb->Lfcb->FileHandle,
  1547. securityInformation,
  1548. transaction->OutData,
  1549. transaction->MaxDataCount,
  1550. &lengthNeeded
  1551. );
  1552. SmbPutUlong( &response->LengthNeeded, lengthNeeded );
  1553. transaction->ParameterCount = sizeof( RESP_QUERY_SECURITY_DESCRIPTOR );
  1554. //
  1555. // If an error occurred, return an appropriate response.
  1556. //
  1557. if ( !NT_SUCCESS(status) ) {
  1558. transaction->DataCount = 0;
  1559. SrvSetSmbError2( WorkContext, status, TRUE );
  1560. return SmbTransStatusErrorWithData;
  1561. } else {
  1562. transaction->DataCount =
  1563. RtlLengthSecurityDescriptor( transaction->OutData );
  1564. }
  1565. return SmbTransStatusSuccess;
  1566. } // SrvSmbQuerySecurityDescriptor
  1567. SMB_TRANS_STATUS
  1568. SrvSmbQueryQuota (
  1569. IN OUT PWORK_CONTEXT WorkContext
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. Processes an NtQueryQuotaInformationFile request. This request arrives in an
  1574. Nt Transaction SMB.
  1575. --*/
  1576. {
  1577. PREQ_NT_QUERY_FS_QUOTA_INFO request;
  1578. PRESP_NT_QUERY_FS_QUOTA_INFO response;
  1579. NTSTATUS status;
  1580. PTRANSACTION transaction;
  1581. PRFCB rfcb;
  1582. PVOID sidList;
  1583. ULONG sidListLength,startSidLength,startSidOffset;
  1584. PVOID sidListBuffer = NULL;
  1585. PULONG startSid = NULL;
  1586. ULONG errorOffset;
  1587. IO_STATUS_BLOCK iosb;
  1588. PAGED_CODE( );
  1589. transaction = WorkContext->Parameters.Transaction;
  1590. request = (PREQ_NT_QUERY_FS_QUOTA_INFO)transaction->InParameters;
  1591. response = (PRESP_NT_QUERY_FS_QUOTA_INFO)transaction->OutParameters;
  1592. //
  1593. // Verify that enough parameter bytes were sent and that we're allowed
  1594. // to return enough parameter bytes.
  1595. //
  1596. if ( transaction->ParameterCount < sizeof( *request ) ||
  1597. transaction->MaxParameterCount < sizeof( *response ) ) {
  1598. //
  1599. // Not enough parameter bytes were sent.
  1600. //
  1601. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1602. return SmbTransStatusErrorWithoutData;
  1603. }
  1604. //
  1605. // Verify the FID. If verified, the RFCB block is referenced
  1606. // and its addresses is stored in the WorkContext block, and the
  1607. // RFCB address is returned.
  1608. //
  1609. rfcb = SrvVerifyFid(
  1610. WorkContext,
  1611. SmbGetUshort( &request->Fid ),
  1612. TRUE,
  1613. NULL, // don't serialize with raw write
  1614. &status
  1615. );
  1616. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1617. //
  1618. // Invalid file ID or write behind error. Reject the request.
  1619. //
  1620. SrvSetSmbError( WorkContext, status );
  1621. return SmbTransStatusErrorWithoutData;
  1622. }
  1623. sidListLength = SmbGetUlong( &request->SidListLength );
  1624. startSidLength = SmbGetUlong( &request->StartSidLength );
  1625. startSidOffset = SmbGetUlong( &request->StartSidOffset );
  1626. //
  1627. // If a Sid List is supplied, make sure it is OK
  1628. //
  1629. if( sidListLength != 0 ) {
  1630. //
  1631. // Length OK?
  1632. //
  1633. if( sidListLength > transaction->DataCount ) {
  1634. SrvSetSmbError( WorkContext, STATUS_INVALID_SID );
  1635. return SmbTransStatusErrorWithoutData;
  1636. }
  1637. sidListBuffer = transaction->InData;
  1638. //
  1639. // Alignment OK?
  1640. //
  1641. if( (ULONG_PTR)sidListBuffer & (sizeof(ULONG)-1) ) {
  1642. SrvSetSmbError( WorkContext, STATUS_INVALID_SID );
  1643. return SmbTransStatusErrorWithoutData;
  1644. }
  1645. //
  1646. // Content OK?
  1647. //
  1648. #if XXX
  1649. status = IopCheckGetQuotaBufferValidity( sidListBuffer, sidListLength, errorOffset );
  1650. if( !NT_SUCCESS( status ) ) {
  1651. SrvSetSmbError( WorkContext, status );
  1652. return SmbTransStatusErrorWithoutData;
  1653. }
  1654. #endif
  1655. }
  1656. // The way the transaction buffers are setup the same buffer pointer is used
  1657. // for the incoming data and the outgoing data. This will not work for
  1658. // NtQueryQuotaInformationFile since the underlying driver zeroes the
  1659. // output buffer before processing the input buffer. This presents us with
  1660. // two options ... (1) we can adjust the copying to be staggerred assuming
  1661. // that we can contain both the buffers into the transaction buffer or (2)
  1662. // allocate anew buffer before calling the QueryQuotaInformationFile.
  1663. // The second approach has been implemented since it is well contained.
  1664. // If this turns out to be a performance problem we will revert back to the
  1665. // first option.
  1666. if (sidListLength + startSidLength > 0 &&
  1667. startSidOffset <= transaction->DataCount &&
  1668. startSidLength <= transaction->DataCount &&
  1669. startSidOffset >= sidListLength &&
  1670. startSidOffset + startSidLength <= transaction->DataCount ) {
  1671. sidListBuffer = ALLOCATE_HEAP( startSidOffset + startSidLength, BlockTypeMisc );
  1672. if (sidListBuffer != NULL) {
  1673. RtlCopyMemory(
  1674. sidListBuffer,
  1675. transaction->InData,
  1676. sidListLength);
  1677. if (startSidLength != 0) {
  1678. startSid = (PULONG)((PBYTE)sidListBuffer + startSidOffset);
  1679. RtlCopyMemory(
  1680. startSid,
  1681. ((PBYTE)transaction->InData + startSidOffset),
  1682. startSidLength);
  1683. }
  1684. }
  1685. } else {
  1686. sidListBuffer = NULL;
  1687. }
  1688. iosb.Information = 0;
  1689. //
  1690. // Go ahead and query the quota information!
  1691. //
  1692. status = NtQueryQuotaInformationFile(
  1693. rfcb->Lfcb->FileHandle,
  1694. &iosb,
  1695. transaction->OutData,
  1696. transaction->MaxDataCount,
  1697. request->ReturnSingleEntry,
  1698. sidListBuffer,
  1699. sidListLength,
  1700. startSid,
  1701. request->RestartScan
  1702. );
  1703. if (sidListBuffer != NULL) {
  1704. FREE_HEAP(sidListBuffer);
  1705. }
  1706. //
  1707. // Paranoia
  1708. //
  1709. if( iosb.Information > transaction->MaxDataCount ) {
  1710. iosb.Information = transaction->MaxDataCount;
  1711. }
  1712. transaction->SetupCount = 0;
  1713. SmbPutUlong( &response->Length, (ULONG)iosb.Information );
  1714. transaction->ParameterCount = sizeof( *response );
  1715. transaction->DataCount = (ULONG)iosb.Information;
  1716. if( !NT_SUCCESS( status ) ) {
  1717. SrvSetSmbError2( WorkContext, status, TRUE );
  1718. return SmbTransStatusErrorWithData;
  1719. }
  1720. return SmbTransStatusSuccess;
  1721. } // SrvSmbQueryQuota
  1722. SMB_TRANS_STATUS
  1723. SrvSmbSetQuota (
  1724. IN OUT PWORK_CONTEXT WorkContext
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. Processes an NtSetQuotaInformationFile request. This request arrives in an
  1729. Nt Transaction SMB.
  1730. --*/
  1731. {
  1732. PREQ_NT_SET_FS_QUOTA_INFO request;
  1733. NTSTATUS status;
  1734. PTRANSACTION transaction;
  1735. PRFCB rfcb;
  1736. PVOID buffer,pQuotaInfo=NULL;
  1737. ULONG errorOffset;
  1738. IO_STATUS_BLOCK iosb;
  1739. PAGED_CODE( );
  1740. transaction = WorkContext->Parameters.Transaction;
  1741. request = (PREQ_NT_SET_FS_QUOTA_INFO)transaction->InParameters;
  1742. //
  1743. // Verify that enough parameter bytes were sent and that we're allowed
  1744. // to return enough parameter bytes.
  1745. //
  1746. if ( transaction->ParameterCount < sizeof( *request ) ) {
  1747. //
  1748. // Not enough parameter bytes were sent.
  1749. //
  1750. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1751. return SmbTransStatusErrorWithoutData;
  1752. }
  1753. //
  1754. // Verify the FID. If verified, the RFCB block is referenced
  1755. // and its addresses is stored in the WorkContext block, and the
  1756. // RFCB address is returned.
  1757. //
  1758. rfcb = SrvVerifyFid(
  1759. WorkContext,
  1760. SmbGetUshort( &request->Fid ),
  1761. TRUE,
  1762. NULL, // don't serialize with raw write
  1763. &status
  1764. );
  1765. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1766. //
  1767. // Invalid file ID or write behind error. Reject the request.
  1768. //
  1769. SrvSetSmbError( WorkContext, status );
  1770. return SmbTransStatusErrorWithoutData;
  1771. }
  1772. //
  1773. // We do not need to check the buffer for validity, because
  1774. // IopSetEaOrQuotaInformationFile does this even for kernel mode callers!
  1775. //
  1776. iosb.Information = 0;
  1777. // we have to do allocation here in order to get a QUAD_WORD
  1778. // aligned pointer. This is so because this is a requirement on
  1779. // alpha for the quota buffer
  1780. pQuotaInfo = ALLOCATE_HEAP_COLD( transaction->DataCount, BlockTypeDataBuffer );
  1781. if (pQuotaInfo)
  1782. {
  1783. RtlCopyMemory(
  1784. pQuotaInfo,
  1785. transaction->InData,
  1786. transaction->DataCount
  1787. );
  1788. //
  1789. // Go ahead and set the quota information!
  1790. //
  1791. status = NtSetQuotaInformationFile(
  1792. rfcb->Lfcb->FileHandle,
  1793. &iosb,
  1794. pQuotaInfo,
  1795. transaction->DataCount
  1796. );
  1797. if( !NT_SUCCESS( status ) ) {
  1798. SrvSetSmbError( WorkContext, status );
  1799. }
  1800. //
  1801. // Nothing to return to the client except the status
  1802. //
  1803. transaction->SetupCount = 0;
  1804. transaction->ParameterCount = 0;
  1805. transaction->DataCount = 0;
  1806. FREE_HEAP(pQuotaInfo);
  1807. }
  1808. else
  1809. {
  1810. SrvSetSmbError( WorkContext, STATUS_INSUFFICIENT_RESOURCES );
  1811. }
  1812. return SmbTransStatusSuccess;
  1813. }