Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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