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.

4204 lines
125 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbattr.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Query Information
  8. Set Information
  9. Query Information2
  10. Set Information2
  11. Query Path Information
  12. Set Path Information
  13. Query File Information
  14. Set File Information
  15. Author:
  16. David Treadwell (davidtr) 27-Dec-1989
  17. Chuck Lenzmeier (chuckl)
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #include "smbattr.tmh"
  22. #pragma hdrstop
  23. #define BugCheckFileId SRV_FILE_SMBATTR
  24. #pragma pack(1)
  25. typedef struct _FILESTATUS {
  26. SMB_DATE CreationDate;
  27. SMB_TIME CreationTime;
  28. SMB_DATE LastAccessDate;
  29. SMB_TIME LastAccessTime;
  30. SMB_DATE LastWriteDate;
  31. SMB_TIME LastWriteTime;
  32. _ULONG( DataSize );
  33. _ULONG( AllocationSize );
  34. _USHORT( Attributes );
  35. _ULONG( EaSize ); // this field intentionally misaligned!
  36. } FILESTATUS, *PFILESTATUS;
  37. #pragma pack()
  38. STATIC
  39. ULONG QueryFileInformation[] = {
  40. SMB_QUERY_FILE_BASIC_INFO,// Base level
  41. FileBasicInformation, // Mapping for base level
  42. FileStandardInformation,
  43. FileEaInformation,
  44. FileNameInformation,
  45. FileAllocationInformation,
  46. FileEndOfFileInformation,
  47. 0, // FileAllInformation
  48. FileAlternateNameInformation,
  49. FileStreamInformation,
  50. 0, //Used to be FileOleAllInformation -- OBSOLETE
  51. FileCompressionInformation
  52. };
  53. STATIC
  54. ULONG QueryFileInformationSize[] = {
  55. SMB_QUERY_FILE_BASIC_INFO,// Base level
  56. FileBasicInformation, // Mapping for base level
  57. sizeof( FILE_BASIC_INFORMATION),
  58. sizeof( FILE_STANDARD_INFORMATION ),
  59. sizeof( FILE_EA_INFORMATION ),
  60. sizeof( FILE_NAME_INFORMATION ),
  61. sizeof( FILE_ALLOCATION_INFORMATION ),
  62. sizeof( FILE_END_OF_FILE_INFORMATION ),
  63. sizeof( FILE_ALL_INFORMATION ),
  64. sizeof( FILE_NAME_INFORMATION ),
  65. sizeof( FILE_STREAM_INFORMATION ),
  66. 0, // Used to be sizeof( FILE_OLE_ALL_INFORMATION )
  67. sizeof( FILE_COMPRESSION_INFORMATION )
  68. };
  69. STATIC
  70. ULONG SetFileInformation[] = {
  71. SMB_SET_FILE_BASIC_INFO, // Base level
  72. FileBasicInformation, // Mapping for base level
  73. FileDispositionInformation,
  74. FileAllocationInformation,
  75. FileEndOfFileInformation
  76. };
  77. STATIC
  78. ULONG SetFileInformationSize[] = {
  79. SMB_SET_FILE_BASIC_INFO, // Base level
  80. FileBasicInformation, // Mapping for base level
  81. sizeof( FILE_BASIC_INFORMATION ),
  82. sizeof( FILE_DISPOSITION_INFORMATION ),
  83. sizeof( FILE_ALLOCATION_INFORMATION ),
  84. sizeof( FILE_END_OF_FILE_INFORMATION )
  85. };
  86. STATIC
  87. NTSTATUS
  88. QueryPathOrFileInformation (
  89. IN PWORK_CONTEXT WorkContext,
  90. IN PTRANSACTION Transaction,
  91. IN USHORT InformationLevel,
  92. IN HANDLE FileHandle,
  93. OUT PRESP_QUERY_PATH_INFORMATION Response
  94. );
  95. STATIC
  96. NTSTATUS
  97. SetPathOrFileInformation (
  98. IN PWORK_CONTEXT WorkContext,
  99. IN PTRANSACTION Transaction,
  100. IN USHORT InformationLevel,
  101. IN HANDLE FileHandle,
  102. OUT PRESP_SET_PATH_INFORMATION Response
  103. );
  104. SMB_TRANS_STATUS
  105. GenerateQueryPathInfoResponse (
  106. IN PWORK_CONTEXT WorkContext,
  107. IN NTSTATUS OpenStatus
  108. );
  109. #ifdef ALLOC_PRAGMA
  110. #pragma alloc_text( PAGE, SrvSmbQueryInformation )
  111. #pragma alloc_text( PAGE, SrvSmbSetInformation )
  112. #pragma alloc_text( PAGE, SrvSmbQueryInformation2 )
  113. #pragma alloc_text( PAGE, SrvSmbSetInformation2 )
  114. #pragma alloc_text( PAGE, QueryPathOrFileInformation )
  115. #pragma alloc_text( PAGE, SrvSmbQueryFileInformation )
  116. #pragma alloc_text( PAGE, SrvSmbQueryPathInformation )
  117. #pragma alloc_text( PAGE, GenerateQueryPathInfoResponse )
  118. #pragma alloc_text( PAGE, SetPathOrFileInformation )
  119. #pragma alloc_text( PAGE, SrvSmbSetFileInformation )
  120. #pragma alloc_text( PAGE, SrvSmbSetPathInformation )
  121. #endif
  122. SMB_PROCESSOR_RETURN_TYPE
  123. SrvSmbQueryInformation (
  124. SMB_PROCESSOR_PARAMETERS
  125. )
  126. /*++
  127. Routine Description:
  128. Processes the QueryInformation SMB.
  129. Arguments:
  130. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  131. of the parameters to SMB processor routines.
  132. Return Value:
  133. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  134. --*/
  135. {
  136. PREQ_QUERY_INFORMATION request;
  137. PRESP_QUERY_INFORMATION response;
  138. NTSTATUS status = STATUS_SUCCESS;
  139. SMB_STATUS SmbStatus = SmbStatusInProgress;
  140. PSESSION session;
  141. PTREE_CONNECT treeConnect;
  142. OBJECT_ATTRIBUTES objectAttributes;
  143. UNICODE_STRING objectName;
  144. IO_STATUS_BLOCK ioStatusBlock;
  145. BOOLEAN isUnicode;
  146. FILE_NETWORK_OPEN_INFORMATION fileInformation;
  147. PAGED_CODE( );
  148. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  149. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_INFORMATION;
  150. SrvWmiStartContext(WorkContext);
  151. IF_SMB_DEBUG(QUERY_SET1) {
  152. KdPrint(( "QueryInformation request header at 0x%p, response header at 0x%p\n",
  153. WorkContext->RequestHeader,
  154. WorkContext->ResponseHeader ));
  155. KdPrint(( "QueryInformation request parameters at 0x%p, response parameters at 0x%p\n",
  156. WorkContext->RequestParameters,
  157. WorkContext->ResponseParameters ));
  158. }
  159. request = (PREQ_QUERY_INFORMATION)WorkContext->RequestParameters;
  160. response = (PRESP_QUERY_INFORMATION)WorkContext->ResponseParameters;
  161. //
  162. // If a session block has not already been assigned to the current
  163. // work context, verify the UID. If verified, the address of the
  164. // session block corresponding to this user is stored in the WorkContext
  165. // block and the session block is referenced.
  166. //
  167. // Find tree connect corresponding to given TID if a tree connect
  168. // pointer has not already been put in the WorkContext block by an
  169. // AndX command.
  170. //
  171. status = SrvVerifyUidAndTid(
  172. WorkContext,
  173. &session,
  174. &treeConnect,
  175. ShareTypeDisk
  176. );
  177. if ( !NT_SUCCESS(status) ) {
  178. IF_DEBUG(SMB_ERRORS) {
  179. KdPrint(( "SrvSmbQueryInformation: Invalid UID or TID\n" ));
  180. }
  181. SrvSetSmbError( WorkContext, status );
  182. SmbStatus = SmbStatusSendResponse;
  183. goto Cleanup;
  184. }
  185. //
  186. // If the session has expired, return that info
  187. //
  188. if( session->IsSessionExpired )
  189. {
  190. status = SESSION_EXPIRED_STATUS_CODE;
  191. SmbStatus = SmbStatusSendResponse;
  192. SrvSetSmbError( WorkContext, status );
  193. goto Cleanup;
  194. }
  195. //
  196. // Get the path name of the file to open relative to the share.
  197. //
  198. isUnicode = SMB_IS_UNICODE( WorkContext );
  199. status = SrvCanonicalizePathName(
  200. WorkContext,
  201. treeConnect->Share,
  202. NULL,
  203. (PVOID)(request->Buffer + 1),
  204. END_OF_REQUEST_SMB( WorkContext ),
  205. TRUE,
  206. isUnicode,
  207. &objectName
  208. );
  209. if( !NT_SUCCESS( status ) ) {
  210. IF_DEBUG(SMB_ERRORS) {
  211. KdPrint(( "SrvSmbQueryInformation: bad path name: %s\n",
  212. (PSZ)request->Buffer + 1 ));
  213. }
  214. SrvSetSmbError( WorkContext, status );
  215. SmbStatus = SmbStatusSendResponse;
  216. goto Cleanup;
  217. }
  218. //
  219. // Initialize the object attributes structure.
  220. //
  221. SrvInitializeObjectAttributes_U(
  222. &objectAttributes,
  223. &objectName,
  224. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  225. session->UsingUppercasePaths) ? OBJ_CASE_INSENSITIVE : 0L,
  226. NULL,
  227. NULL
  228. );
  229. //
  230. // "Be the client" for access checking
  231. //
  232. status = IMPERSONATE( WorkContext );
  233. if( NT_SUCCESS( status ) ) {
  234. status = SrvGetShareRootHandle( treeConnect->Share );
  235. if( NT_SUCCESS( status ) ) {
  236. //
  237. // The file name is always relative to the share root
  238. //
  239. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  240. if( !NT_SUCCESS( status ) )
  241. {
  242. goto SnapError;
  243. }
  244. //
  245. // Get the information
  246. //
  247. if( IoFastQueryNetworkAttributes(
  248. &objectAttributes,
  249. FILE_READ_ATTRIBUTES,
  250. 0,
  251. &ioStatusBlock,
  252. &fileInformation
  253. ) == FALSE ) {
  254. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  255. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  256. }
  257. status = ioStatusBlock.Status;
  258. //
  259. // If the media was changed and we can come up with a new share root handle,
  260. // then we should retry the operation
  261. //
  262. if( SrvRetryDueToDismount( treeConnect->Share, status ) ) {
  263. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  264. if( !NT_SUCCESS( status ) )
  265. {
  266. goto SnapError;
  267. }
  268. if( IoFastQueryNetworkAttributes(
  269. &objectAttributes,
  270. FILE_READ_ATTRIBUTES,
  271. 0,
  272. &ioStatusBlock,
  273. &fileInformation
  274. ) == FALSE ) {
  275. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  276. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  277. }
  278. status = ioStatusBlock.Status;
  279. }
  280. SnapError:
  281. SrvReleaseShareRootHandle( treeConnect->Share );
  282. }
  283. REVERT();
  284. }
  285. if ( !isUnicode ) {
  286. RtlFreeUnicodeString( &objectName );
  287. }
  288. //
  289. // Build the response SMB.
  290. //
  291. if ( !NT_SUCCESS(status) ) {
  292. if ( status == STATUS_ACCESS_DENIED ) {
  293. SrvStatistics.AccessPermissionErrors++;
  294. }
  295. IF_DEBUG(ERRORS) {
  296. KdPrint(( "SrvSmbQueryInformation: "
  297. "SrvQueryInformationFileAbbreviated failed: %X\n", status ));
  298. }
  299. SrvSetSmbError( WorkContext, status );
  300. } else {
  301. USHORT smbFileAttributes;
  302. LARGE_INTEGER newTime;
  303. response->WordCount = 10;
  304. SRV_NT_ATTRIBUTES_TO_SMB(
  305. fileInformation.FileAttributes,
  306. fileInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY,
  307. &smbFileAttributes
  308. );
  309. SmbPutUshort( &response->FileAttributes, smbFileAttributes );
  310. //
  311. // Convert the time to that which the SMB protocol needs
  312. //
  313. ExSystemTimeToLocalTime( &fileInformation.LastWriteTime, &newTime );
  314. newTime.QuadPart += AlmostTwoSeconds;
  315. if ( !RtlTimeToSecondsSince1970( &newTime, &fileInformation.LastWriteTime.LowPart ) ) {
  316. fileInformation.LastWriteTime.LowPart = 0;
  317. }
  318. //
  319. // Round to 2 seconds
  320. //
  321. fileInformation.LastWriteTime.LowPart &= ~1;
  322. SmbPutUlong(
  323. &response->LastWriteTimeInSeconds,
  324. fileInformation.LastWriteTime.LowPart
  325. );
  326. SmbPutUlong( &response->FileSize, fileInformation.EndOfFile.LowPart );
  327. RtlZeroMemory( (PVOID)&response->Reserved[0], sizeof(response->Reserved) );
  328. SmbPutUshort( &response->ByteCount, 0 );
  329. WorkContext->ResponseParameters = NEXT_LOCATION(
  330. response,
  331. RESP_QUERY_INFORMATION,
  332. 0
  333. );
  334. }
  335. SmbStatus = SmbStatusSendResponse;
  336. Cleanup:
  337. SrvWmiEndContext(WorkContext);
  338. return SmbStatus;
  339. } // SrvSmbQueryInformation
  340. SMB_PROCESSOR_RETURN_TYPE
  341. SrvSmbSetInformation (
  342. SMB_PROCESSOR_PARAMETERS
  343. )
  344. /*++
  345. Routine Description:
  346. Processes the SetInformation SMB.
  347. Arguments:
  348. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  349. of the parameters to SMB processor routines.
  350. Return Value:
  351. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  352. --*/
  353. {
  354. PREQ_SET_INFORMATION request;
  355. PRESP_SET_INFORMATION response;
  356. NTSTATUS status = STATUS_SUCCESS;
  357. SMB_STATUS SmbStatus = SmbStatusInProgress;
  358. PSESSION session;
  359. PTREE_CONNECT treeConnect;
  360. HANDLE fileHandle;
  361. OBJECT_ATTRIBUTES objectAttributes;
  362. UNICODE_STRING objectName;
  363. IO_STATUS_BLOCK ioStatusBlock;
  364. BOOLEAN isUnicode;
  365. FILE_BASIC_INFORMATION fileBasicInformation;
  366. ULONG lastWriteTimeInSeconds;
  367. PAGED_CODE( );
  368. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  369. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SET_INFORMATION;
  370. SrvWmiStartContext(WorkContext);
  371. IF_SMB_DEBUG(QUERY_SET1) {
  372. KdPrint(( "SetInformation request header at 0x%p, response header at 0x%p\n",
  373. WorkContext->RequestHeader,
  374. WorkContext->ResponseHeader ));
  375. KdPrint(( "SetInformation request parameters at 0x%p, response parameters at 0x%p\n",
  376. WorkContext->RequestParameters,
  377. WorkContext->ResponseParameters ));
  378. }
  379. request = (PREQ_SET_INFORMATION)WorkContext->RequestParameters;
  380. response = (PRESP_SET_INFORMATION)WorkContext->ResponseParameters;
  381. //
  382. // If a session block has not already been assigned to the current
  383. // work context, verify the UID. If verified, the address of the
  384. // session block corresponding to this user is stored in the WorkContext
  385. // block and the session block is referenced.
  386. //
  387. // Find tree connect corresponding to given TID if a tree connect
  388. // pointer has not already been put in the WorkContext block by an
  389. // AndX command.
  390. //
  391. status = SrvVerifyUidAndTid(
  392. WorkContext,
  393. &session,
  394. &treeConnect,
  395. ShareTypeDisk
  396. );
  397. if ( !NT_SUCCESS(status) ) {
  398. IF_DEBUG(SMB_ERRORS) {
  399. KdPrint(( "SrvSmbSetInformation: Invalid UID and TID\n" ));
  400. }
  401. SrvSetSmbError( WorkContext, status );
  402. SmbStatus = SmbStatusSendResponse;
  403. goto Cleanup;
  404. }
  405. //
  406. // If the session has expired, return that info
  407. //
  408. if( session->IsSessionExpired )
  409. {
  410. status = SESSION_EXPIRED_STATUS_CODE;
  411. SmbStatus = SmbStatusSendResponse;
  412. SrvSetSmbError( WorkContext, status );
  413. goto Cleanup;
  414. }
  415. if ( treeConnect == NULL ) {
  416. IF_DEBUG(SMB_ERRORS) {
  417. KdPrint(( "SrvSmbSetInformation: Invalid TID: 0x%lx\n",
  418. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid ) ));
  419. }
  420. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_TID );
  421. SmbStatus = SmbStatusSendResponse;
  422. goto Cleanup;
  423. }
  424. //
  425. // Concatenate PathName from the share block and PathName from the
  426. // incoming SMB to generate the full path name to the file.
  427. //
  428. isUnicode = SMB_IS_UNICODE( WorkContext );
  429. status = SrvCanonicalizePathName(
  430. WorkContext,
  431. treeConnect->Share,
  432. NULL,
  433. (PVOID)(request->Buffer + 1),
  434. END_OF_REQUEST_SMB( WorkContext ),
  435. TRUE,
  436. isUnicode,
  437. &objectName
  438. );
  439. if( !NT_SUCCESS( status ) ) {
  440. IF_DEBUG(SMB_ERRORS) {
  441. KdPrint(( "SrvSmbSetInformation: bad path name: %s\n",
  442. (PSZ)request->Buffer + 1 ));
  443. }
  444. SrvSetSmbError( WorkContext, status );
  445. SmbStatus = SmbStatusSendResponse;
  446. goto Cleanup;
  447. }
  448. //
  449. // If the client is trying to delete the root of the share, reject
  450. // the request.
  451. //
  452. if ( objectName.Length < sizeof(WCHAR) ) {
  453. IF_DEBUG(SMB_ERRORS) {
  454. KdPrint(( "SrvSmbSetInformation: attempting to set info on "
  455. "share root\n" ));
  456. }
  457. if (!SMB_IS_UNICODE( WorkContext )) {
  458. RtlFreeUnicodeString( &objectName );
  459. }
  460. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  461. SmbStatus = SmbStatusSendResponse;
  462. goto Cleanup;
  463. }
  464. //
  465. // Initialize the object attributes structure.
  466. //
  467. SrvInitializeObjectAttributes_U(
  468. &objectAttributes,
  469. &objectName,
  470. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  471. session->UsingUppercasePaths) ? OBJ_CASE_INSENSITIVE : 0L,
  472. NULL,
  473. NULL
  474. );
  475. IF_SMB_DEBUG(QUERY_SET2) KdPrint(( "Opening file %wZ\n", &objectName ));
  476. //
  477. // Open the file--must be opened in order to have a handle to pass
  478. // to NtSetInformationFile. We will close it after setting the
  479. // necessary information.
  480. //
  481. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  482. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  483. //
  484. // *** FILE_WRITE_ATTRIBUTES does not cause oplock breaks!
  485. //
  486. status = SrvIoCreateFile(
  487. WorkContext,
  488. &fileHandle,
  489. FILE_WRITE_ATTRIBUTES, // DesiredAccess
  490. &objectAttributes,
  491. &ioStatusBlock,
  492. NULL, // AllocationSize
  493. 0, // FileAttributes
  494. FILE_SHARE_READ | FILE_SHARE_WRITE |
  495. FILE_SHARE_DELETE, // ShareAccess
  496. FILE_OPEN, // Disposition
  497. FILE_OPEN_REPARSE_POINT, // CreateOptions
  498. NULL, // EaBuffer
  499. 0, // EaLength
  500. CreateFileTypeNone,
  501. NULL, // ExtraCreateParameters
  502. IO_FORCE_ACCESS_CHECK, // Options
  503. treeConnect->Share
  504. );
  505. if( status == STATUS_INVALID_PARAMETER ) {
  506. status = SrvIoCreateFile(
  507. WorkContext,
  508. &fileHandle,
  509. FILE_WRITE_ATTRIBUTES, // DesiredAccess
  510. &objectAttributes,
  511. &ioStatusBlock,
  512. NULL, // AllocationSize
  513. 0, // FileAttributes
  514. FILE_SHARE_READ | FILE_SHARE_WRITE |
  515. FILE_SHARE_DELETE, // ShareAccess
  516. FILE_OPEN, // Disposition
  517. 0, // CreateOptions
  518. NULL, // EaBuffer
  519. 0, // EaLength
  520. CreateFileTypeNone,
  521. NULL, // ExtraCreateParameters
  522. IO_FORCE_ACCESS_CHECK, // Options
  523. treeConnect->Share
  524. );
  525. }
  526. ASSERT( status != STATUS_OPLOCK_BREAK_IN_PROGRESS );
  527. if ( !isUnicode ) {
  528. RtlFreeUnicodeString( &objectName );
  529. }
  530. if ( NT_SUCCESS(status) ) {
  531. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 20, 0 );
  532. //
  533. // Ensure this client's RFCB cache is empty. This covers the case
  534. // where a client opened a file for writing, closed it, set the
  535. // attributes to readonly, and then tried to reopen the file for
  536. // writing. This sequence should fail, but it will succeed if the
  537. // file was in the RFCB cache.
  538. //
  539. SrvCloseCachedRfcbsOnConnection( WorkContext->Connection );
  540. } else {
  541. if ( status == STATUS_ACCESS_DENIED ) {
  542. SrvStatistics.AccessPermissionErrors++;
  543. }
  544. IF_DEBUG(ERRORS) {
  545. KdPrint(( "SrvSmbSetInformation: SrvIoCreateFile "
  546. "failed: %X\n", status ));
  547. }
  548. SrvSetSmbError( WorkContext, status );
  549. SmbStatus = SmbStatusSendResponse;
  550. goto Cleanup;
  551. }
  552. IF_SMB_DEBUG(QUERY_SET2) {
  553. KdPrint(( "SrvIoCreateFile succeeded, handle = 0x%p\n", fileHandle ));
  554. }
  555. //
  556. // Set fields of fileBasicInformation to pass to NtSetInformationFile.
  557. // Note that we zero the creation, last access, and change times so
  558. // that they are not actually changed.
  559. //
  560. RtlZeroMemory( &fileBasicInformation, sizeof(fileBasicInformation) );
  561. lastWriteTimeInSeconds = SmbGetUlong( &request->LastWriteTimeInSeconds );
  562. if ( lastWriteTimeInSeconds != 0 ) {
  563. RtlSecondsSince1970ToTime(
  564. lastWriteTimeInSeconds,
  565. &fileBasicInformation.LastWriteTime
  566. );
  567. ExLocalTimeToSystemTime(
  568. &fileBasicInformation.LastWriteTime,
  569. &fileBasicInformation.LastWriteTime
  570. );
  571. }
  572. //
  573. // Set the new file attributes. Note that we don't return an error
  574. // if the client tries to set the Directory or Volume bits -- we
  575. // assume that the remote redirector filters such requests.
  576. //
  577. SRV_SMB_ATTRIBUTES_TO_NT(
  578. SmbGetUshort( &request->FileAttributes ),
  579. NULL,
  580. &fileBasicInformation.FileAttributes
  581. );
  582. //
  583. // Set the new file information.
  584. //
  585. status = NtSetInformationFile(
  586. fileHandle,
  587. &ioStatusBlock,
  588. &fileBasicInformation,
  589. sizeof(FILE_BASIC_INFORMATION),
  590. FileBasicInformation
  591. );
  592. //
  593. // Close the file--it was only opened to set the attributes.
  594. //
  595. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 30, 0 );
  596. SrvNtClose( fileHandle, TRUE );
  597. if ( !NT_SUCCESS(status) ) {
  598. INTERNAL_ERROR(
  599. ERROR_LEVEL_UNEXPECTED,
  600. "SrvSmbSetInformation: NtSetInformationFile returned %X",
  601. status,
  602. NULL
  603. );
  604. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  605. SrvSetSmbError( WorkContext, status );
  606. SmbStatus = SmbStatusSendResponse;
  607. goto Cleanup;
  608. }
  609. //
  610. // Build the response SMB.
  611. //
  612. response->WordCount = 0;
  613. SmbPutUshort( &response->ByteCount, 0 );
  614. WorkContext->ResponseParameters = NEXT_LOCATION(
  615. response,
  616. RESP_SET_INFORMATION,
  617. 0
  618. );
  619. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSetInformation complete.\n" ));
  620. SmbStatus = SmbStatusSendResponse;
  621. Cleanup:
  622. SrvWmiEndContext(WorkContext);
  623. return SmbStatus;
  624. } // SrvSmbSetInformation
  625. SMB_PROCESSOR_RETURN_TYPE
  626. SrvSmbQueryInformation2 (
  627. SMB_PROCESSOR_PARAMETERS
  628. )
  629. /*++
  630. Routine Description:
  631. Processes the QueryInformation2 SMB.
  632. Arguments:
  633. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  634. of the parameters to SMB processor routines.
  635. Return Value:
  636. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  637. --*/
  638. {
  639. PREQ_QUERY_INFORMATION2 request;
  640. PRESP_QUERY_INFORMATION2 response;
  641. NTSTATUS status = STATUS_SUCCESS;
  642. SMB_STATUS SmbStatus = SmbStatusInProgress;
  643. PRFCB rfcb;
  644. SRV_FILE_INFORMATION fileInformation;
  645. PAGED_CODE( );
  646. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  647. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_INFORMATION2;
  648. SrvWmiStartContext(WorkContext);
  649. IF_SMB_DEBUG(QUERY_SET1) {
  650. KdPrint(( "QueryInformation2 request header at 0x%p, response header at 0x%p\n",
  651. WorkContext->RequestHeader,
  652. WorkContext->ResponseHeader ));
  653. KdPrint(( "QueryInformation2 request parameters at 0x%p, response parameters at 0x%p\n",
  654. WorkContext->RequestParameters,
  655. WorkContext->ResponseParameters ));
  656. }
  657. request = (PREQ_QUERY_INFORMATION2)WorkContext->RequestParameters;
  658. response = (PRESP_QUERY_INFORMATION2)WorkContext->ResponseParameters;
  659. //
  660. // Verify the FID. If verified, the RFCB block is referenced
  661. // and its addresses is stored in the WorkContext block, and the
  662. // RFCB address is returned.
  663. //
  664. rfcb = SrvVerifyFid(
  665. WorkContext,
  666. SmbGetUshort( &request->Fid ),
  667. TRUE,
  668. SrvRestartSmbReceived, // serialize with raw write
  669. &status
  670. );
  671. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  672. if ( !NT_SUCCESS( status ) ) {
  673. //
  674. // Invalid file ID or write behind error. Reject the request.
  675. //
  676. IF_DEBUG(ERRORS) {
  677. KdPrint((
  678. "SrvSmbQueryInformation2: Status %X on fid 0x%lx\n",
  679. status,
  680. SmbGetUshort( &request->Fid )
  681. ));
  682. }
  683. SrvSetSmbError( WorkContext, status );
  684. SmbStatus = SmbStatusSendResponse;
  685. goto Cleanup;
  686. }
  687. //
  688. // The work item has been queued because a raw write is in
  689. // progress.
  690. //
  691. SmbStatus = SmbStatusInProgress;
  692. goto Cleanup;
  693. }
  694. if( rfcb->Lfcb->Session->IsSessionExpired )
  695. {
  696. status = SESSION_EXPIRED_STATUS_CODE;
  697. SrvSetSmbError( WorkContext, status );
  698. SmbStatus = SmbStatusSendResponse;
  699. goto Cleanup;
  700. }
  701. //
  702. // Verify that the client has read attributes access to the file via
  703. // the specified handle.
  704. //
  705. CHECK_FILE_INFORMATION_ACCESS(
  706. rfcb->GrantedAccess,
  707. IRP_MJ_QUERY_INFORMATION,
  708. FileBasicInformation,
  709. &status
  710. );
  711. if ( !NT_SUCCESS(status) ) {
  712. SrvStatistics.GrantedAccessErrors++;
  713. IF_DEBUG(ERRORS) {
  714. KdPrint(( "SrvSmbQueryInformation2: IoCheckFunctionAccess failed: "
  715. "0x%X, GrantedAccess: %lx\n",
  716. status, rfcb->GrantedAccess ));
  717. }
  718. SrvSetSmbError( WorkContext, status );
  719. SmbStatus = SmbStatusSendResponse;
  720. goto Cleanup;
  721. }
  722. //
  723. // Get the necessary information about the file.
  724. //
  725. status = SrvQueryInformationFile(
  726. rfcb->Lfcb->FileHandle,
  727. rfcb->Lfcb->FileObject,
  728. &fileInformation,
  729. (SHARE_TYPE) -1,
  730. FALSE
  731. );
  732. if ( !NT_SUCCESS(status) ) {
  733. INTERNAL_ERROR(
  734. ERROR_LEVEL_UNEXPECTED,
  735. "SrvSmbQueryInformation2: SrvQueryInformationFile returned %X",
  736. status,
  737. NULL
  738. );
  739. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  740. SrvSetSmbError( WorkContext, status );
  741. SmbStatus = SmbStatusSendResponse;
  742. goto Cleanup;
  743. }
  744. //
  745. // Build the response SMB.
  746. //
  747. response->WordCount = 11;
  748. SmbPutDate( &response->CreationDate, fileInformation.CreationDate );
  749. SmbPutTime( &response->CreationTime, fileInformation.CreationTime );
  750. SmbPutDate( &response->LastAccessDate, fileInformation.LastAccessDate );
  751. SmbPutTime( &response->LastAccessTime, fileInformation.LastAccessTime );
  752. SmbPutDate( &response->LastWriteDate, fileInformation.LastWriteDate );
  753. SmbPutTime( &response->LastWriteTime, fileInformation.LastWriteTime );
  754. SmbPutUlong( &response->FileDataSize, fileInformation.DataSize.LowPart );
  755. SmbPutUlong(
  756. &response->FileAllocationSize,
  757. fileInformation.AllocationSize.LowPart
  758. );
  759. SmbPutUshort( &response->FileAttributes, fileInformation.Attributes );
  760. SmbPutUshort( &response->ByteCount, 0 );
  761. WorkContext->ResponseParameters = NEXT_LOCATION(
  762. response,
  763. RESP_QUERY_INFORMATION2,
  764. 0
  765. );
  766. SmbStatus = SmbStatusSendResponse;
  767. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbQueryInformation2 complete.\n" ));
  768. Cleanup:
  769. SrvWmiEndContext(WorkContext);
  770. return SmbStatus;
  771. } // SrvSmbQueryInformation2
  772. SMB_PROCESSOR_RETURN_TYPE
  773. SrvSmbSetInformation2 (
  774. SMB_PROCESSOR_PARAMETERS
  775. )
  776. /*++
  777. Routine Description:
  778. Processes the Set Information2 SMB.
  779. Arguments:
  780. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  781. of the parameters to SMB processor routines.
  782. Return Value:
  783. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  784. --*/
  785. {
  786. PREQ_SET_INFORMATION2 request;
  787. PRESP_SET_INFORMATION2 response;
  788. NTSTATUS status = STATUS_SUCCESS;
  789. SMB_STATUS SmbStatus = SmbStatusInProgress;
  790. PRFCB rfcb;
  791. FILE_BASIC_INFORMATION fileBasicInformation;
  792. IO_STATUS_BLOCK ioStatusBlock;
  793. SMB_DATE date;
  794. SMB_TIME time;
  795. PAGED_CODE( );
  796. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  797. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SET_INFORMATION2;
  798. SrvWmiStartContext(WorkContext);
  799. IF_SMB_DEBUG(QUERY_SET1) {
  800. KdPrint(( "SetInformation2 request header at 0x%p, response header at 0x%p\n",
  801. WorkContext->RequestHeader,
  802. WorkContext->ResponseHeader ));
  803. KdPrint(( "SetInformation2 request parameters at 0x%p, response parameters at 0x%p\n",
  804. WorkContext->RequestParameters,
  805. WorkContext->ResponseParameters ));
  806. }
  807. request = (PREQ_SET_INFORMATION2)WorkContext->RequestParameters;
  808. response = (PRESP_SET_INFORMATION2)WorkContext->ResponseParameters;
  809. //
  810. // Verify the FID. If verified, the RFCB block is referenced
  811. // and its addresses is stored in the WorkContext block, and the
  812. // RFCB address is returned.
  813. //
  814. rfcb = SrvVerifyFid(
  815. WorkContext,
  816. SmbGetUshort( &request->Fid ),
  817. TRUE,
  818. SrvRestartSmbReceived, // serialize with raw write
  819. &status
  820. );
  821. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  822. if ( !NT_SUCCESS( status ) ) {
  823. //
  824. // Invalid file ID or write behind error. Reject the request.
  825. //
  826. IF_DEBUG(ERRORS) {
  827. KdPrint((
  828. "SrvSmbSetInformation2: Status %X on fid 0x%lx\n",
  829. status,
  830. SmbGetUshort( &request->Fid )
  831. ));
  832. }
  833. SrvSetSmbError( WorkContext, status );
  834. SmbStatus = SmbStatusSendResponse;
  835. goto Cleanup;
  836. }
  837. //
  838. // The work item has been queued because a raw write is in
  839. // progress.
  840. //
  841. SmbStatus = SmbStatusInProgress;
  842. goto Cleanup;
  843. }
  844. if( rfcb->Lfcb->Session->IsSessionExpired )
  845. {
  846. status = SESSION_EXPIRED_STATUS_CODE;
  847. SrvSetSmbError( WorkContext, status );
  848. SmbStatus = SmbStatusSendResponse;
  849. goto Cleanup;
  850. }
  851. //
  852. // Verify that the client has write attributes access to the file
  853. // via the specified handle.
  854. //
  855. CHECK_FILE_INFORMATION_ACCESS(
  856. rfcb->GrantedAccess,
  857. IRP_MJ_SET_INFORMATION,
  858. FileBasicInformation,
  859. &status
  860. );
  861. if ( !NT_SUCCESS(status) ) {
  862. SrvStatistics.GrantedAccessErrors++;
  863. IF_DEBUG(ERRORS) {
  864. KdPrint(( "SrvSmbSetInformation2: IoCheckFunctionAccess failed: "
  865. "0x%X, GrantedAccess: %lx\n",
  866. status, rfcb->GrantedAccess ));
  867. }
  868. SrvSetSmbError( WorkContext, status );
  869. SmbStatus = SmbStatusSendResponse;
  870. goto Cleanup;
  871. }
  872. //
  873. // Convert the DOS dates and times passed in the SMB to NT TIMEs
  874. // to pass to NtSetInformationFile. Note that we zero the rest
  875. // of the fileBasicInformation structure so that the corresponding
  876. // fields are not changed.
  877. //
  878. RtlZeroMemory( &fileBasicInformation, sizeof(fileBasicInformation) );
  879. SmbMoveDate( &date, &request->CreationDate );
  880. SmbMoveTime( &time, &request->CreationTime );
  881. if ( !SmbIsDateZero(&date) || !SmbIsTimeZero(&time) ) {
  882. SrvDosTimeToTime( &fileBasicInformation.CreationTime, date, time );
  883. }
  884. SmbMoveDate( &date, &request->LastAccessDate );
  885. SmbMoveTime( &time, &request->LastAccessTime );
  886. if ( !SmbIsDateZero(&date) || !SmbIsTimeZero(&time) ) {
  887. SrvDosTimeToTime( &fileBasicInformation.LastAccessTime, date, time );
  888. }
  889. SmbMoveDate( &date, &request->LastWriteDate );
  890. SmbMoveTime( &time, &request->LastWriteTime );
  891. if ( !SmbIsDateZero(&date) || !SmbIsTimeZero(&time) ) {
  892. SrvDosTimeToTime( &fileBasicInformation.LastWriteTime, date, time );
  893. }
  894. //
  895. // Call NtSetInformationFile to set the information from the SMB.
  896. //
  897. status = NtSetInformationFile(
  898. rfcb->Lfcb->FileHandle,
  899. &ioStatusBlock,
  900. &fileBasicInformation,
  901. sizeof(FILE_BASIC_INFORMATION),
  902. FileBasicInformation
  903. );
  904. if ( !NT_SUCCESS(status) ) {
  905. INTERNAL_ERROR(
  906. ERROR_LEVEL_UNEXPECTED,
  907. "SrvSmbSetInformation2: NtSetInformationFile failed: %X",
  908. status,
  909. NULL
  910. );
  911. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  912. SrvSetSmbError( WorkContext, status );
  913. SmbStatus = SmbStatusSendResponse;
  914. goto Cleanup;
  915. }
  916. #ifdef INCLUDE_SMB_IFMODIFIED
  917. rfcb->Lfcb->FileUpdated = TRUE;
  918. #endif
  919. //
  920. // reset the WrittenTo flag. This will allow this rfcb to be cached.
  921. //
  922. rfcb->WrittenTo = FALSE;
  923. //
  924. // Build the response SMB.
  925. //
  926. response->WordCount = 0;
  927. SmbPutUshort( &response->ByteCount, 0 );
  928. WorkContext->ResponseParameters = NEXT_LOCATION(
  929. response,
  930. RESP_SET_INFORMATION2,
  931. 0
  932. );
  933. SmbStatus = SmbStatusSendResponse;
  934. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSetInformation2 complete.\n" ));
  935. Cleanup:
  936. SrvWmiEndContext(WorkContext);
  937. return SmbStatus;
  938. } // SrvSmbSetInformation2
  939. STATIC
  940. NTSTATUS
  941. QueryPathOrFileInformation (
  942. IN PWORK_CONTEXT WorkContext,
  943. IN PTRANSACTION Transaction,
  944. IN USHORT InformationLevel,
  945. IN HANDLE FileHandle,
  946. OUT PRESP_QUERY_PATH_INFORMATION Response
  947. )
  948. {
  949. NTSTATUS status;
  950. IO_STATUS_BLOCK ioStatusBlock;
  951. SRV_FILE_INFORMATION fileInformation;
  952. BOOLEAN queryEaSize;
  953. USHORT eaErrorOffset;
  954. PFILE_ALL_INFORMATION fileAllInformation;
  955. ULONG nameInformationSize;
  956. PVOID currentLocation;
  957. ULONG dataSize;
  958. PUNICODE_STRING pathName;
  959. ULONG inputBufferLength;
  960. PPATHNAME_BUFFER inputBuffer;
  961. PFILE_NAME_INFORMATION nameInfoBuffer;
  962. PSHARE share;
  963. PAGED_CODE( );
  964. Transaction->SetupCount = 0;
  965. Transaction->ParameterCount = 0;
  966. if( InformationLevel < SMB_INFO_PASSTHROUGH ) {
  967. switch ( InformationLevel ) {
  968. case SMB_INFO_STANDARD:
  969. case SMB_INFO_QUERY_EA_SIZE:
  970. //
  971. // Information level is either STANDARD or QUERY_EA_SIZE. Both
  972. // return normal file information; the latter also returns the
  973. // length of the file's EAs.
  974. //
  975. queryEaSize = (BOOLEAN)(InformationLevel == SMB_INFO_QUERY_EA_SIZE);
  976. status = SrvQueryInformationFile(
  977. FileHandle,
  978. NULL,
  979. &fileInformation,
  980. (SHARE_TYPE) -1, // Don't care
  981. queryEaSize
  982. );
  983. if ( NT_SUCCESS(status) ) {
  984. //
  985. // Build the output parameter and data structures.
  986. //
  987. PFILESTATUS fileStatus = (PFILESTATUS)Transaction->OutData;
  988. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  989. SmbPutUshort( &Response->EaErrorOffset, 0 );
  990. Transaction->DataCount = queryEaSize ? 26 : 22;
  991. SmbPutDate(
  992. &fileStatus->CreationDate,
  993. fileInformation.CreationDate
  994. );
  995. SmbPutTime(
  996. &fileStatus->CreationTime,
  997. fileInformation.CreationTime
  998. );
  999. SmbPutDate(
  1000. &fileStatus->LastAccessDate,
  1001. fileInformation.LastAccessDate
  1002. );
  1003. SmbPutTime(
  1004. &fileStatus->LastAccessTime,
  1005. fileInformation.LastAccessTime
  1006. );
  1007. SmbPutDate(
  1008. &fileStatus->LastWriteDate,
  1009. fileInformation.LastWriteDate
  1010. );
  1011. SmbPutTime(
  1012. &fileStatus->LastWriteTime,
  1013. fileInformation.LastWriteTime
  1014. );
  1015. SmbPutUlong( &fileStatus->DataSize, fileInformation.DataSize.LowPart );
  1016. SmbPutUlong(
  1017. &fileStatus->AllocationSize,
  1018. fileInformation.AllocationSize.LowPart
  1019. );
  1020. SmbPutUshort(
  1021. &fileStatus->Attributes,
  1022. fileInformation.Attributes
  1023. );
  1024. if ( queryEaSize ) {
  1025. SmbPutUlong( &fileStatus->EaSize, fileInformation.EaSize );
  1026. }
  1027. } else {
  1028. //
  1029. // Set the data count to zero so that no data is returned to the
  1030. // client.
  1031. //
  1032. Transaction->DataCount = 0;
  1033. INTERNAL_ERROR(
  1034. ERROR_LEVEL_UNEXPECTED,
  1035. "QueryPathOrFileInformation: SrvQueryInformationFile"
  1036. "returned %X",
  1037. status,
  1038. NULL
  1039. );
  1040. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  1041. }
  1042. break;
  1043. case SMB_INFO_QUERY_EAS_FROM_LIST:
  1044. case SMB_INFO_QUERY_ALL_EAS:
  1045. //
  1046. // The request is for EAs, either all of them or a subset.
  1047. //
  1048. status = SrvQueryOs2FeaList(
  1049. FileHandle,
  1050. InformationLevel == SMB_INFO_QUERY_EAS_FROM_LIST ?
  1051. (PGEALIST)Transaction->InData : NULL,
  1052. NULL,
  1053. Transaction->DataCount,
  1054. (PFEALIST)Transaction->OutData,
  1055. Transaction->MaxDataCount,
  1056. &eaErrorOffset
  1057. );
  1058. if ( NT_SUCCESS(status) ) {
  1059. //
  1060. // The first longword of the OutData buffer holds the length
  1061. // of the remaining data written (the cbList field of the
  1062. // FEALIST). Add four (the longword itself) to get the number
  1063. // of data bytes written.
  1064. //
  1065. Transaction->DataCount =
  1066. SmbGetAlignedUlong( (PULONG)Transaction->OutData );
  1067. #if 0
  1068. //
  1069. // If there were no EAs, convert the error to
  1070. // STATUS_NO_EAS_ON_FILE. OS/2 clients expect STATUS_SUCCESS.
  1071. //
  1072. if ( (Transaction->DataCount == 4) &&
  1073. IS_NT_DIALECT( Transaction->Connection->SmbDialect ) ) {
  1074. status = STATUS_NO_EAS_ON_FILE;
  1075. }
  1076. #endif
  1077. } else {
  1078. IF_DEBUG(ERRORS) {
  1079. KdPrint(( "QueryPathOrFileInformation: "
  1080. "SrvQueryOs2FeaList failed: %X\n", status ));
  1081. }
  1082. Transaction->DataCount = 0;
  1083. }
  1084. //
  1085. // Build the output parameter and data structures.
  1086. //
  1087. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1088. SmbPutUshort( &Response->EaErrorOffset, eaErrorOffset );
  1089. break;
  1090. case SMB_INFO_IS_NAME_VALID:
  1091. status = STATUS_SUCCESS;
  1092. Transaction->DataCount = 0;
  1093. break;
  1094. case SMB_QUERY_FILE_BASIC_INFO:
  1095. case SMB_QUERY_FILE_STANDARD_INFO:
  1096. case SMB_QUERY_FILE_EA_INFO:
  1097. case SMB_QUERY_FILE_ALT_NAME_INFO:
  1098. case SMB_QUERY_FILE_STREAM_INFO:
  1099. case SMB_QUERY_FILE_COMPRESSION_INFO:
  1100. //
  1101. // Pass the data buffer directly to the file system as it
  1102. // is already in NT format.
  1103. //
  1104. if( Transaction->MaxDataCount <
  1105. MAP_SMB_INFO_TO_MIN_NT_SIZE(QueryFileInformationSize, InformationLevel ) ) {
  1106. //
  1107. // The buffer is too small. Return an error.
  1108. //
  1109. status = STATUS_INFO_LENGTH_MISMATCH;
  1110. } else {
  1111. status = NtQueryInformationFile(
  1112. FileHandle,
  1113. &ioStatusBlock,
  1114. Transaction->OutData,
  1115. Transaction->MaxDataCount,
  1116. MAP_SMB_INFO_TYPE_TO_NT(
  1117. QueryFileInformation,
  1118. InformationLevel
  1119. )
  1120. );
  1121. }
  1122. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1123. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1124. if (NT_SUCCESS( status) || (status == STATUS_BUFFER_OVERFLOW)) {
  1125. Transaction->DataCount = (ULONG)ioStatusBlock.Information;
  1126. } else {
  1127. Transaction->DataCount = 0;
  1128. }
  1129. break;
  1130. case SMB_QUERY_FILE_NAME_INFO:
  1131. DoFileNameInfo:
  1132. share = Transaction->TreeConnect->Share;
  1133. nameInfoBuffer = (PFILE_NAME_INFORMATION)Transaction->OutData;
  1134. if ( Transaction->MaxDataCount < FIELD_OFFSET(FILE_NAME_INFORMATION,FileName) ) {
  1135. //
  1136. // The buffer is too small to fit even the fixed part.
  1137. // Return an error.
  1138. //
  1139. status = STATUS_INFO_LENGTH_MISMATCH;
  1140. Transaction->DataCount = 0;
  1141. } else if ( share->ShareType != ShareTypeDisk ) {
  1142. //
  1143. // This is not a disk share. Pass the request straight to
  1144. // the file system.
  1145. //
  1146. status = NtQueryInformationFile(
  1147. FileHandle,
  1148. &ioStatusBlock,
  1149. nameInfoBuffer,
  1150. Transaction->MaxDataCount,
  1151. FileNameInformation
  1152. );
  1153. Transaction->DataCount = (ULONG)ioStatusBlock.Information;
  1154. } else {
  1155. //
  1156. // We need a temporary buffer since the file system will
  1157. // return the share path together with the file name. The
  1158. // total length might be larger than the max data allowed
  1159. // in the transaction, though the actual name might fit.
  1160. //
  1161. PFILE_NAME_INFORMATION tempBuffer;
  1162. ULONG tempBufferLength;
  1163. ASSERT( share->QueryNamePrefixLength >= 0 );
  1164. tempBufferLength = Transaction->MaxDataCount + share->QueryNamePrefixLength;
  1165. tempBuffer = ALLOCATE_HEAP( tempBufferLength, BlockTypeBuffer );
  1166. if ( tempBuffer == NULL ) {
  1167. status = STATUS_INSUFF_SERVER_RESOURCES;
  1168. } else {
  1169. status = NtQueryInformationFile(
  1170. FileHandle,
  1171. &ioStatusBlock,
  1172. tempBuffer,
  1173. tempBufferLength,
  1174. FileNameInformation
  1175. );
  1176. }
  1177. //
  1178. // remove the share part
  1179. //
  1180. if ( (status == STATUS_SUCCESS) || (status == STATUS_BUFFER_OVERFLOW) ) {
  1181. LONG bytesToMove;
  1182. PWCHAR source;
  1183. WCHAR slash = L'\\';
  1184. //
  1185. // Calculate how long the name string is, not including the root prefix.
  1186. //
  1187. bytesToMove = (LONG)(tempBuffer->FileNameLength - share->QueryNamePrefixLength);
  1188. if ( bytesToMove <= 0 ) {
  1189. //
  1190. // bytesToMove will be zero if this is the root of
  1191. // the share. Return just a \ for this case.
  1192. //
  1193. bytesToMove = sizeof(WCHAR);
  1194. source = &slash;
  1195. } else {
  1196. source = tempBuffer->FileName + share->QueryNamePrefixLength/sizeof(WCHAR);
  1197. }
  1198. //
  1199. // Store the actual file name length.
  1200. //
  1201. SmbPutUlong( &nameInfoBuffer->FileNameLength, bytesToMove );
  1202. //
  1203. // If the buffer isn't big enough, return an error and
  1204. // reduce the amount to be copied.
  1205. //
  1206. if ( (ULONG)bytesToMove >
  1207. (Transaction->MaxDataCount -
  1208. FIELD_OFFSET(FILE_NAME_INFORMATION,FileName)) ) {
  1209. status = STATUS_BUFFER_OVERFLOW;
  1210. bytesToMove = Transaction->MaxDataCount -
  1211. FIELD_OFFSET(FILE_NAME_INFORMATION,FileName);
  1212. } else {
  1213. status = STATUS_SUCCESS;
  1214. }
  1215. //
  1216. // Copy all but the prefix.
  1217. //
  1218. RtlCopyMemory(
  1219. nameInfoBuffer->FileName,
  1220. source,
  1221. bytesToMove
  1222. );
  1223. Transaction->DataCount =
  1224. FIELD_OFFSET(FILE_NAME_INFORMATION,FileName) + bytesToMove;
  1225. } else {
  1226. Transaction->DataCount = 0;
  1227. }
  1228. if ( tempBuffer != NULL ) {
  1229. FREE_HEAP( tempBuffer );
  1230. }
  1231. }
  1232. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1233. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1234. break;
  1235. case SMB_QUERY_FILE_ALL_INFO:
  1236. DoFileAllInfo:
  1237. //
  1238. // Setup early for the response in case the call to the file
  1239. // system fails.
  1240. //
  1241. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1242. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1243. //
  1244. // Allocate a buffer large enough to return all the information.
  1245. // The buffer size we request is the size requested by the client
  1246. // plus room for the extra information returned by the file system
  1247. // that the server doesn't return to the client.
  1248. //
  1249. dataSize = Transaction->MaxDataCount +
  1250. sizeof( FILE_ALL_INFORMATION )
  1251. - sizeof( FILE_BASIC_INFORMATION )
  1252. - sizeof( FILE_STANDARD_INFORMATION )
  1253. - sizeof( FILE_EA_INFORMATION )
  1254. - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName );
  1255. fileAllInformation = ALLOCATE_HEAP_COLD( dataSize, BlockTypeDataBuffer );
  1256. if ( fileAllInformation == NULL ) {
  1257. status = STATUS_INSUFFICIENT_RESOURCES;
  1258. break;
  1259. }
  1260. status = NtQueryInformationFile(
  1261. FileHandle,
  1262. &ioStatusBlock,
  1263. fileAllInformation,
  1264. dataSize,
  1265. FileAllInformation
  1266. );
  1267. if ( NT_SUCCESS( status ) ) {
  1268. //
  1269. // Calculate the size of data we will return. We do not
  1270. // return the entire buffer, just specific fields.
  1271. //
  1272. nameInformationSize =
  1273. FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) +
  1274. fileAllInformation->NameInformation.FileNameLength;
  1275. Transaction->DataCount =
  1276. sizeof( FILE_BASIC_INFORMATION ) +
  1277. sizeof( FILE_STANDARD_INFORMATION ) +
  1278. sizeof( FILE_EA_INFORMATION ) +
  1279. nameInformationSize;
  1280. //
  1281. // Now copy the data into the transaction buffer. Start with
  1282. // the fixed sized fields.
  1283. //
  1284. currentLocation = Transaction->OutData;
  1285. *((PFILE_BASIC_INFORMATION)currentLocation)++ =
  1286. fileAllInformation->BasicInformation;
  1287. *((PFILE_STANDARD_INFORMATION)currentLocation)++ =
  1288. fileAllInformation->StandardInformation;
  1289. *((PFILE_EA_INFORMATION)currentLocation)++ =
  1290. fileAllInformation->EaInformation;
  1291. RtlCopyMemory(
  1292. currentLocation,
  1293. &fileAllInformation->NameInformation,
  1294. nameInformationSize
  1295. );
  1296. } else {
  1297. Transaction->DataCount = 0;
  1298. }
  1299. FREE_HEAP( fileAllInformation );
  1300. break;
  1301. default:
  1302. IF_DEBUG(SMB_ERRORS) {
  1303. KdPrint(( "QueryPathOrFileInformation: bad info level %d\n",
  1304. InformationLevel ));
  1305. }
  1306. status = STATUS_INVALID_SMB;
  1307. break;
  1308. }
  1309. } else {
  1310. InformationLevel -= SMB_INFO_PASSTHROUGH;
  1311. if( InformationLevel == FileNameInformation ) {
  1312. goto DoFileNameInfo;
  1313. } else if( InformationLevel == FileAllInformation ) {
  1314. goto DoFileAllInfo;
  1315. }
  1316. //
  1317. // See if the supplied parameters are correct.
  1318. //
  1319. status = IoCheckQuerySetFileInformation( InformationLevel,
  1320. Transaction->MaxDataCount,
  1321. FALSE );
  1322. if( NT_SUCCESS( status ) ) {
  1323. //
  1324. // Some information levels require us to impersonate the client. Do it for all.
  1325. //
  1326. status = IMPERSONATE( WorkContext );
  1327. if( NT_SUCCESS( status ) ) {
  1328. status = NtQueryInformationFile(
  1329. FileHandle,
  1330. &ioStatusBlock,
  1331. Transaction->OutData,
  1332. Transaction->MaxDataCount,
  1333. InformationLevel
  1334. );
  1335. REVERT();
  1336. }
  1337. }
  1338. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1339. Transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1340. if (NT_SUCCESS( status) || (status == STATUS_BUFFER_OVERFLOW)) {
  1341. Transaction->DataCount = (ULONG)ioStatusBlock.Information;
  1342. } else {
  1343. Transaction->DataCount = 0;
  1344. }
  1345. }
  1346. return status;
  1347. } // QueryPathOrFileInformation
  1348. SMB_TRANS_STATUS
  1349. SrvSmbQueryFileInformation (
  1350. IN OUT PWORK_CONTEXT WorkContext
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Processes the Query File Information request. This request arrives
  1355. in a Transaction2 SMB. Query File Information corresponds to the
  1356. OS/2 DosQFileInfo service.
  1357. Arguments:
  1358. WorkContext - Supplies the address of a Work Context Block
  1359. describing the current request. See smbtypes.h for a more
  1360. complete description of the valid fields.
  1361. Return Value:
  1362. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  1363. whether data should be returned to the client. See smbtypes.h
  1364. for a more complete description.
  1365. --*/
  1366. {
  1367. PREQ_QUERY_FILE_INFORMATION request;
  1368. PRESP_QUERY_FILE_INFORMATION response;
  1369. NTSTATUS status = STATUS_SUCCESS;
  1370. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  1371. PTRANSACTION transaction;
  1372. PRFCB rfcb;
  1373. USHORT informationLevel;
  1374. ACCESS_MASK grantedAccess;
  1375. PAGED_CODE( );
  1376. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1377. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_FILE_INFORMATION;
  1378. SrvWmiStartContext(WorkContext);
  1379. transaction = WorkContext->Parameters.Transaction;
  1380. IF_SMB_DEBUG(QUERY_SET1) {
  1381. KdPrint(( "Query File Information entered; transaction 0x%p\n",
  1382. transaction ));
  1383. }
  1384. request = (PREQ_QUERY_FILE_INFORMATION)transaction->InParameters;
  1385. response = (PRESP_QUERY_FILE_INFORMATION)transaction->OutParameters;
  1386. //
  1387. // Verify that enough parameter bytes were sent and that we're allowed
  1388. // to return enough parameter bytes.
  1389. //
  1390. if ( (transaction->ParameterCount <
  1391. sizeof(REQ_QUERY_FILE_INFORMATION)) ||
  1392. (transaction->MaxParameterCount <
  1393. sizeof(RESP_QUERY_FILE_INFORMATION)) ) {
  1394. //
  1395. // Not enough parameter bytes were sent.
  1396. //
  1397. IF_SMB_DEBUG(QUERY_SET1) {
  1398. KdPrint(( "SrvSmbQueryFileInformation: bad parameter byte counts: "
  1399. "%ld %ld\n",
  1400. transaction->ParameterCount,
  1401. transaction->MaxParameterCount ));
  1402. }
  1403. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1404. status = STATUS_INVALID_SMB;
  1405. SmbStatus = SmbTransStatusErrorWithoutData;
  1406. goto Cleanup;
  1407. }
  1408. //
  1409. // Verify the FID. If verified, the RFCB block is referenced
  1410. // and its addresses is stored in the WorkContext block, and the
  1411. // RFCB address is returned.
  1412. //
  1413. rfcb = SrvVerifyFid(
  1414. WorkContext,
  1415. SmbGetUshort( &request->Fid ),
  1416. TRUE,
  1417. SrvRestartExecuteTransaction, // serialize with raw write
  1418. &status
  1419. );
  1420. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1421. if ( !NT_SUCCESS( status ) ) {
  1422. //
  1423. // Invalid file ID or write behind error. Reject the request.
  1424. //
  1425. IF_DEBUG(ERRORS) {
  1426. KdPrint((
  1427. "SrvSmbQueryFileInformation: Status %X on FID: 0x%lx\n",
  1428. status,
  1429. SmbGetUshort( &request->Fid )
  1430. ));
  1431. }
  1432. SrvSetSmbError( WorkContext, status );
  1433. SmbStatus = SmbTransStatusErrorWithoutData;
  1434. goto Cleanup;
  1435. }
  1436. //
  1437. // The work item has been queued because a raw write is in
  1438. // progress.
  1439. //
  1440. SmbStatus = SmbTransStatusInProgress;
  1441. goto Cleanup;
  1442. }
  1443. //
  1444. //
  1445. // Verify the information level and the number of input and output
  1446. // data bytes available.
  1447. //
  1448. informationLevel = SmbGetUshort( &request->InformationLevel );
  1449. grantedAccess = rfcb->GrantedAccess;
  1450. status = STATUS_SUCCESS;
  1451. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  1452. switch ( informationLevel ) {
  1453. case SMB_INFO_STANDARD:
  1454. if ( transaction->MaxDataCount < 22 ) {
  1455. IF_DEBUG(SMB_ERRORS) {
  1456. KdPrint(( "SrvSmbQueryFileInformation: invalid MaxDataCount "
  1457. "%ld\n", transaction->MaxDataCount ));
  1458. }
  1459. status = STATUS_INVALID_SMB;
  1460. break;
  1461. }
  1462. //
  1463. // Verify that the client has read attributes access to the file
  1464. // via the specified handle.
  1465. //
  1466. CHECK_FILE_INFORMATION_ACCESS(
  1467. grantedAccess,
  1468. IRP_MJ_QUERY_INFORMATION,
  1469. FileBasicInformation,
  1470. &status
  1471. );
  1472. IF_DEBUG(ERRORS) {
  1473. if ( !NT_SUCCESS(status) ) {
  1474. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1475. "failed: 0x%X, GrantedAccess: %lx\n",
  1476. status, grantedAccess ));
  1477. }
  1478. }
  1479. break;
  1480. case SMB_INFO_QUERY_EA_SIZE:
  1481. if ( transaction->MaxDataCount < 26 ) {
  1482. IF_DEBUG(SMB_ERRORS) {
  1483. KdPrint(( "SrvSmbQueryFileInformation: invalid MaxDataCount "
  1484. "%ld\n", transaction->MaxDataCount ));
  1485. }
  1486. status = STATUS_INVALID_SMB;
  1487. break;
  1488. }
  1489. //
  1490. // Verify that the client has read EA access to the file via the
  1491. // specified handle.
  1492. //
  1493. CHECK_FILE_INFORMATION_ACCESS(
  1494. grantedAccess,
  1495. IRP_MJ_QUERY_INFORMATION,
  1496. FileEaInformation,
  1497. &status
  1498. );
  1499. IF_DEBUG(SMB_ERRORS) {
  1500. if ( !NT_SUCCESS(status) ) {
  1501. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1502. "failed: 0x%X, GrantedAccess: %lx\n",
  1503. status, grantedAccess ));
  1504. }
  1505. }
  1506. break;
  1507. case SMB_INFO_QUERY_EAS_FROM_LIST:
  1508. case SMB_INFO_QUERY_ALL_EAS:
  1509. //
  1510. // Verify that the client has read EA access to the file via the
  1511. // specified handle.
  1512. //
  1513. CHECK_FUNCTION_ACCESS(
  1514. grantedAccess,
  1515. IRP_MJ_QUERY_EA,
  1516. 0,
  1517. 0,
  1518. &status
  1519. );
  1520. IF_DEBUG(ERRORS) {
  1521. if ( !NT_SUCCESS(status) ) {
  1522. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1523. "failed: 0x%X, GrantedAccess: %lx\n",
  1524. status, grantedAccess ));
  1525. }
  1526. }
  1527. break;
  1528. case SMB_QUERY_FILE_BASIC_INFO:
  1529. CHECK_FILE_INFORMATION_ACCESS(
  1530. grantedAccess,
  1531. IRP_MJ_QUERY_INFORMATION,
  1532. FileBasicInformation,
  1533. &status
  1534. );
  1535. IF_DEBUG(ERRORS) {
  1536. if ( !NT_SUCCESS(status) ) {
  1537. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1538. "failed: 0x%X, GrantedAccess: %lx\n",
  1539. status, grantedAccess ));
  1540. }
  1541. }
  1542. break;
  1543. case SMB_QUERY_FILE_STANDARD_INFO:
  1544. CHECK_FILE_INFORMATION_ACCESS(
  1545. grantedAccess,
  1546. IRP_MJ_QUERY_INFORMATION,
  1547. FileStandardInformation,
  1548. &status
  1549. );
  1550. IF_DEBUG(ERRORS) {
  1551. if ( !NT_SUCCESS(status) ) {
  1552. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1553. "failed: 0x%X, GrantedAccess: %lx\n",
  1554. status, grantedAccess ));
  1555. }
  1556. }
  1557. break;
  1558. case SMB_QUERY_FILE_EA_INFO:
  1559. CHECK_FILE_INFORMATION_ACCESS(
  1560. grantedAccess,
  1561. IRP_MJ_QUERY_INFORMATION,
  1562. FileEaInformation,
  1563. &status
  1564. );
  1565. IF_DEBUG(ERRORS) {
  1566. if ( !NT_SUCCESS(status) ) {
  1567. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1568. "failed: 0x%X, GrantedAccess: %lx\n",
  1569. status, grantedAccess ));
  1570. }
  1571. }
  1572. break;
  1573. case SMB_QUERY_FILE_NAME_INFO:
  1574. CHECK_FILE_INFORMATION_ACCESS(
  1575. grantedAccess,
  1576. IRP_MJ_QUERY_INFORMATION,
  1577. FileNameInformation,
  1578. &status
  1579. );
  1580. IF_DEBUG(ERRORS) {
  1581. if ( !NT_SUCCESS(status) ) {
  1582. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1583. "failed: 0x%X, GrantedAccess: %lx\n",
  1584. status, grantedAccess ));
  1585. }
  1586. }
  1587. break;
  1588. case SMB_QUERY_FILE_ALL_INFO:
  1589. CHECK_FILE_INFORMATION_ACCESS(
  1590. grantedAccess,
  1591. IRP_MJ_QUERY_INFORMATION,
  1592. FileAllInformation,
  1593. &status
  1594. );
  1595. IF_DEBUG(ERRORS) {
  1596. if ( !NT_SUCCESS(status) ) {
  1597. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1598. "failed: 0x%X, GrantedAccess: %lx\n",
  1599. status, grantedAccess ));
  1600. }
  1601. }
  1602. break;
  1603. case SMB_QUERY_FILE_ALT_NAME_INFO:
  1604. CHECK_FILE_INFORMATION_ACCESS(
  1605. grantedAccess,
  1606. IRP_MJ_QUERY_INFORMATION,
  1607. FileAlternateNameInformation,
  1608. &status
  1609. );
  1610. IF_DEBUG(ERRORS) {
  1611. if ( !NT_SUCCESS(status) ) {
  1612. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1613. "failed: 0x%X, GrantedAccess: %lx\n",
  1614. status, grantedAccess ));
  1615. }
  1616. }
  1617. break;
  1618. case SMB_QUERY_FILE_STREAM_INFO:
  1619. CHECK_FILE_INFORMATION_ACCESS(
  1620. grantedAccess,
  1621. IRP_MJ_QUERY_INFORMATION,
  1622. FileStreamInformation,
  1623. &status
  1624. );
  1625. IF_DEBUG(ERRORS) {
  1626. if ( !NT_SUCCESS(status) ) {
  1627. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1628. "failed: 0x%X, GrantedAccess: %lx\n",
  1629. status, grantedAccess ));
  1630. }
  1631. }
  1632. break;
  1633. case SMB_QUERY_FILE_COMPRESSION_INFO:
  1634. CHECK_FILE_INFORMATION_ACCESS(
  1635. grantedAccess,
  1636. IRP_MJ_QUERY_INFORMATION,
  1637. FileCompressionInformation,
  1638. &status
  1639. );
  1640. IF_DEBUG(ERRORS) {
  1641. if ( !NT_SUCCESS(status) ) {
  1642. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  1643. "failed: 0x%X, GrantedAccess: %lx\n",
  1644. status, grantedAccess ));
  1645. }
  1646. }
  1647. break;
  1648. default:
  1649. IF_DEBUG(SMB_ERRORS) {
  1650. KdPrint(( "SrvSmbQueryFileInformation: invalid info level %ld\n",
  1651. informationLevel ));
  1652. }
  1653. status = STATUS_OS2_INVALID_LEVEL;
  1654. break;
  1655. }
  1656. } else {
  1657. if( informationLevel - SMB_INFO_PASSTHROUGH >= FileMaximumInformation ) {
  1658. status = STATUS_INVALID_INFO_CLASS;
  1659. }
  1660. if( NT_SUCCESS( status ) ) {
  1661. status = IoCheckQuerySetFileInformation( informationLevel - SMB_INFO_PASSTHROUGH,
  1662. 0xFFFFFFFF,
  1663. FALSE
  1664. );
  1665. }
  1666. if( NT_SUCCESS( status ) ) {
  1667. CHECK_FILE_INFORMATION_ACCESS(
  1668. grantedAccess,
  1669. IRP_MJ_QUERY_INFORMATION,
  1670. informationLevel - SMB_INFO_PASSTHROUGH,
  1671. &status
  1672. );
  1673. }
  1674. }
  1675. if ( !NT_SUCCESS(status) ) {
  1676. SrvSetSmbError( WorkContext, status );
  1677. SmbStatus = SmbTransStatusErrorWithoutData;
  1678. goto Cleanup;
  1679. }
  1680. //
  1681. // Get the necessary information about the file.
  1682. //
  1683. status = QueryPathOrFileInformation(
  1684. WorkContext,
  1685. transaction,
  1686. informationLevel,
  1687. rfcb->Lfcb->FileHandle,
  1688. (PRESP_QUERY_PATH_INFORMATION)response
  1689. );
  1690. //
  1691. // Map STATUS_BUFFER_OVERFLOW for OS/2 clients.
  1692. //
  1693. if ( status == STATUS_BUFFER_OVERFLOW &&
  1694. !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  1695. status = STATUS_BUFFER_TOO_SMALL;
  1696. }
  1697. //
  1698. // If an error occurred, return an appropriate response.
  1699. //
  1700. if ( !NT_SUCCESS(status) ) {
  1701. //
  1702. // QueryPathOrFileInformation already filled in the response
  1703. // information, so just set the error and return.
  1704. //
  1705. SrvSetSmbError2( WorkContext, status, TRUE );
  1706. SmbStatus = SmbTransStatusErrorWithData;
  1707. goto Cleanup;
  1708. }
  1709. SmbStatus = SmbTransStatusSuccess;
  1710. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbQueryFileInformation complete.\n" ));
  1711. Cleanup:
  1712. SrvWmiEndContext(WorkContext);
  1713. return SmbStatus;
  1714. } // SrvSmbQueryFileInformation
  1715. SMB_TRANS_STATUS
  1716. SrvSmbQueryPathInformation (
  1717. IN OUT PWORK_CONTEXT WorkContext
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. Processes the Query Path Information request. This request arrives
  1722. in a Transaction2 SMB. Query Path Information corresponds to the
  1723. OS/2 DosQPathInfo service.
  1724. Arguments:
  1725. WorkContext - Supplies the address of a Work Context Block
  1726. describing the current request. See smbtypes.h for a more
  1727. complete description of the valid fields.
  1728. Return Value:
  1729. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  1730. whether data should be returned to the client. See smbtypes.h
  1731. for a more complete description.
  1732. --*/
  1733. {
  1734. PTRANSACTION transaction;
  1735. PREQ_QUERY_PATH_INFORMATION request;
  1736. PRESP_QUERY_PATH_INFORMATION response;
  1737. USHORT informationLevel;
  1738. NTSTATUS status = STATUS_SUCCESS;
  1739. HANDLE fileHandle;
  1740. IO_STATUS_BLOCK ioStatusBlock;
  1741. OBJECT_ATTRIBUTES objectAttributes;
  1742. UNICODE_STRING objectName;
  1743. BOOLEAN isUnicode;
  1744. SMB_TRANS_STATUS smbStatus = SmbTransStatusInProgress;
  1745. ACCESS_MASK desiredAccess;
  1746. PAGED_CODE( );
  1747. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1748. WorkContext->PreviousSMB = EVENT_TYPE_SMB_QUERY_PATH_INFORMATION;
  1749. SrvWmiStartContext(WorkContext);
  1750. transaction = WorkContext->Parameters.Transaction;
  1751. IF_SMB_DEBUG(QUERY_SET1) {
  1752. KdPrint(( "Query Path Information entered; transaction 0x%p\n",
  1753. transaction ));
  1754. }
  1755. //
  1756. // Verify that enough parameter bytes were sent and that we're allowed
  1757. // to return enough parameter bytes.
  1758. //
  1759. if ( (transaction->ParameterCount <
  1760. sizeof(REQ_QUERY_PATH_INFORMATION)) ||
  1761. (transaction->MaxParameterCount <
  1762. sizeof(RESP_QUERY_PATH_INFORMATION)) ) {
  1763. //
  1764. // Not enough parameter bytes were sent.
  1765. //
  1766. IF_DEBUG(SMB_ERRORS) {
  1767. KdPrint(( "SrvSmbQueryPathInformation: bad parameter byte "
  1768. "counts: %ld %ld\n",
  1769. transaction->ParameterCount,
  1770. transaction->MaxParameterCount ));
  1771. }
  1772. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1773. status = STATUS_INVALID_SMB;
  1774. smbStatus = SmbTransStatusErrorWithoutData;
  1775. goto Cleanup;
  1776. }
  1777. request = (PREQ_QUERY_PATH_INFORMATION)transaction->InParameters;
  1778. informationLevel = SmbGetUshort( &request->InformationLevel );
  1779. //
  1780. // The response formats for Query Path and Query File and identical,
  1781. // so just use the RESP_QUERY_PATH_INFORMATION structure for both.
  1782. // The request formats differ, so conditionalize access to them.
  1783. //
  1784. response = (PRESP_QUERY_PATH_INFORMATION)transaction->OutParameters;
  1785. switch( informationLevel ) {
  1786. case SMB_INFO_QUERY_EA_SIZE:
  1787. case SMB_INFO_QUERY_EAS_FROM_LIST:
  1788. case SMB_INFO_QUERY_ALL_EAS:
  1789. //
  1790. // For these info levels, we must be in a blocking thread because we
  1791. // might end up waiting for an oplock break.
  1792. //
  1793. if( WorkContext->UsingBlockingThread == 0 ) {
  1794. WorkContext->FspRestartRoutine = SrvRestartExecuteTransaction;
  1795. SrvQueueWorkToBlockingThread( WorkContext );
  1796. smbStatus = SmbTransStatusInProgress;
  1797. goto Cleanup;
  1798. }
  1799. desiredAccess = FILE_READ_EA;
  1800. break;
  1801. default:
  1802. desiredAccess = FILE_READ_ATTRIBUTES;
  1803. break;
  1804. }
  1805. //
  1806. // Make sure the client is allowed to do this, if we have an Admin share
  1807. //
  1808. status = SrvIsAllowedOnAdminShare( WorkContext, WorkContext->TreeConnect->Share );
  1809. if( !NT_SUCCESS( status ) ) {
  1810. SrvSetSmbError( WorkContext, status );
  1811. smbStatus = SmbTransStatusErrorWithoutData;
  1812. goto Cleanup;
  1813. }
  1814. //
  1815. // Get the path name of the file to open relative to the share.
  1816. //
  1817. isUnicode = SMB_IS_UNICODE( WorkContext );
  1818. status = SrvCanonicalizePathName(
  1819. WorkContext,
  1820. WorkContext->TreeConnect->Share,
  1821. NULL,
  1822. request->Buffer,
  1823. END_OF_TRANSACTION_PARAMETERS( transaction ),
  1824. TRUE,
  1825. isUnicode,
  1826. &objectName
  1827. );
  1828. if( !NT_SUCCESS( status ) ) {
  1829. IF_DEBUG(SMB_ERRORS) {
  1830. KdPrint(( "SrvSmbQueryPathInformation: bad path name: %s\n",
  1831. request->Buffer ));
  1832. }
  1833. SrvSetSmbError( WorkContext, status );
  1834. smbStatus = SmbTransStatusErrorWithoutData;
  1835. goto Cleanup;
  1836. }
  1837. //
  1838. // Special case: If this is the IS_PATH_VALID information level, then
  1839. // the user just wants to know if the path syntax is correct. Do not
  1840. // attempt to open the file.
  1841. //
  1842. informationLevel = SmbGetUshort( &request->InformationLevel );
  1843. if ( informationLevel == SMB_INFO_IS_NAME_VALID ) {
  1844. transaction->InData = (PVOID)&objectName;
  1845. //
  1846. // Get the Share root handle.
  1847. //
  1848. smbStatus = SrvGetShareRootHandle( WorkContext->TreeConnect->Share );
  1849. if ( !NT_SUCCESS(smbStatus) ) {
  1850. IF_DEBUG(ERRORS) {
  1851. KdPrint(( "SrvSmbQueryPathInformation: SrvGetShareRootHandle failed %x.\n",
  1852. smbStatus ));
  1853. }
  1854. if (!isUnicode) {
  1855. RtlFreeUnicodeString( &objectName );
  1856. }
  1857. SrvSetSmbError( WorkContext, smbStatus );
  1858. status = smbStatus;
  1859. smbStatus = SmbTransStatusErrorWithoutData;
  1860. goto Cleanup;
  1861. }
  1862. status = SrvSnapGetRootHandle( WorkContext, &WorkContext->Parameters2.FileInformation.FileHandle );
  1863. if( !NT_SUCCESS(status) )
  1864. {
  1865. SrvSetSmbError( WorkContext, status );
  1866. smbStatus = SmbTransStatusErrorWithoutData;
  1867. goto Cleanup;
  1868. }
  1869. smbStatus = GenerateQueryPathInfoResponse(
  1870. WorkContext,
  1871. SmbTransStatusSuccess
  1872. );
  1873. //
  1874. // Release the root handle for removable devices
  1875. //
  1876. SrvReleaseShareRootHandle( WorkContext->TreeConnect->Share );
  1877. if ( !isUnicode ) {
  1878. RtlFreeUnicodeString( &objectName );
  1879. }
  1880. goto Cleanup;
  1881. }
  1882. //
  1883. // Initialize the object attributes structure.
  1884. //
  1885. SrvInitializeObjectAttributes_U(
  1886. &objectAttributes,
  1887. &objectName,
  1888. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  1889. transaction->Session->UsingUppercasePaths) ?
  1890. OBJ_CASE_INSENSITIVE : 0L,
  1891. NULL,
  1892. NULL
  1893. );
  1894. //
  1895. // Take the fast path for this if we can
  1896. //
  1897. if( informationLevel == SMB_QUERY_FILE_BASIC_INFO ) {
  1898. FILE_NETWORK_OPEN_INFORMATION fileInformation;
  1899. UNALIGNED FILE_BASIC_INFORMATION *pbInfo = (PFILE_BASIC_INFORMATION)transaction->OutData;
  1900. if( transaction->MaxDataCount < sizeof( FILE_BASIC_INFORMATION ) ) {
  1901. SrvSetSmbError( WorkContext, STATUS_INFO_LENGTH_MISMATCH );
  1902. status = STATUS_INFO_LENGTH_MISMATCH;
  1903. smbStatus = SmbTransStatusErrorWithoutData;
  1904. goto Cleanup;
  1905. }
  1906. status = IMPERSONATE( WorkContext );
  1907. if( NT_SUCCESS( status ) ) {
  1908. status = SrvGetShareRootHandle( transaction->TreeConnect->Share );
  1909. if( NT_SUCCESS( status ) ) {
  1910. //
  1911. // The file name is always relative to the share root
  1912. //
  1913. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  1914. if( !NT_SUCCESS(status) )
  1915. {
  1916. goto SnapError;
  1917. }
  1918. //
  1919. // Get the information
  1920. //
  1921. if( IoFastQueryNetworkAttributes(
  1922. &objectAttributes,
  1923. FILE_READ_ATTRIBUTES,
  1924. 0,
  1925. &ioStatusBlock,
  1926. &fileInformation
  1927. ) == FALSE ) {
  1928. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  1929. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1930. }
  1931. status = ioStatusBlock.Status;
  1932. //
  1933. // If the media was changed and we can come up with a new share root handle,
  1934. // then we should retry the operation
  1935. //
  1936. if( SrvRetryDueToDismount( transaction->TreeConnect->Share, status ) ) {
  1937. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  1938. if( !NT_SUCCESS(status) )
  1939. {
  1940. goto SnapError;
  1941. }
  1942. //
  1943. // Get the information
  1944. //
  1945. if( IoFastQueryNetworkAttributes(
  1946. &objectAttributes,
  1947. FILE_READ_ATTRIBUTES,
  1948. 0,
  1949. &ioStatusBlock,
  1950. &fileInformation
  1951. ) == FALSE ) {
  1952. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  1953. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1954. }
  1955. status = ioStatusBlock.Status;
  1956. }
  1957. SnapError:
  1958. SrvReleaseShareRootHandle( transaction->TreeConnect->Share );
  1959. }
  1960. REVERT();
  1961. }
  1962. if( status == STATUS_BUFFER_OVERFLOW ) {
  1963. goto hard_way;
  1964. }
  1965. if ( !isUnicode ) {
  1966. RtlFreeUnicodeString( &objectName );
  1967. }
  1968. if ( !NT_SUCCESS( status ) ) {
  1969. if ( status == STATUS_ACCESS_DENIED ) {
  1970. SrvStatistics.AccessPermissionErrors++;
  1971. }
  1972. IF_DEBUG(ERRORS) {
  1973. KdPrint(( "SrvSmbQueryPathInformation: IoFastQueryNetworkAttributes "
  1974. "failed: %X\n", status ));
  1975. }
  1976. SrvSetSmbError( WorkContext, status );
  1977. smbStatus = SmbTransStatusErrorWithoutData;
  1978. goto Cleanup;
  1979. }
  1980. // FORMULATE THE RESPONSE
  1981. transaction->SetupCount = 0;
  1982. transaction->DataCount = sizeof( *pbInfo );
  1983. transaction->ParameterCount = sizeof( RESP_QUERY_FILE_INFORMATION );
  1984. SmbPutUshort( &response->EaErrorOffset, 0 );
  1985. pbInfo->CreationTime = fileInformation.CreationTime;
  1986. pbInfo->LastAccessTime = fileInformation.LastAccessTime;
  1987. pbInfo->LastWriteTime = fileInformation.LastWriteTime;
  1988. pbInfo->ChangeTime = fileInformation.ChangeTime;
  1989. pbInfo->FileAttributes = fileInformation.FileAttributes;
  1990. smbStatus = SmbTransStatusSuccess;
  1991. goto Cleanup;
  1992. }
  1993. hard_way:
  1994. IF_SMB_DEBUG(QUERY_SET2) KdPrint(( "Opening file %wZ\n", &objectName ));
  1995. //
  1996. // Open the file -- must be opened in order to have a handle to pass
  1997. // to NtQueryInformationFile. We will close it after getting the
  1998. // necessary information.
  1999. //
  2000. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  2001. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  2002. //
  2003. // !!! We may block if the file is oplocked. We must do this, because
  2004. // it is required to get the FS to break a batch oplock.
  2005. // We should figure out a way to do this without blocking.
  2006. //
  2007. status = SrvIoCreateFile(
  2008. WorkContext,
  2009. &fileHandle,
  2010. desiredAccess,
  2011. &objectAttributes,
  2012. &ioStatusBlock,
  2013. NULL, // AllocationSize
  2014. 0, // FileAttributes
  2015. FILE_SHARE_READ | FILE_SHARE_WRITE |
  2016. FILE_SHARE_DELETE, // ShareAccess
  2017. FILE_OPEN, // Disposition
  2018. FILE_OPEN_REPARSE_POINT, // CreateOptions
  2019. NULL, // EaBuffer
  2020. 0, // EaLength
  2021. CreateFileTypeNone,
  2022. NULL, // ExtraCreateParameters
  2023. IO_FORCE_ACCESS_CHECK, // Options
  2024. transaction->TreeConnect->Share
  2025. );
  2026. if( status == STATUS_INVALID_PARAMETER ) {
  2027. status = SrvIoCreateFile(
  2028. WorkContext,
  2029. &fileHandle,
  2030. desiredAccess,
  2031. &objectAttributes,
  2032. &ioStatusBlock,
  2033. NULL, // AllocationSize
  2034. 0, // FileAttributes
  2035. FILE_SHARE_READ | FILE_SHARE_WRITE |
  2036. FILE_SHARE_DELETE, // ShareAccess
  2037. FILE_OPEN, // Disposition
  2038. 0, // CreateOptions
  2039. NULL, // EaBuffer
  2040. 0, // EaLength
  2041. CreateFileTypeNone,
  2042. NULL, // ExtraCreateParameters
  2043. IO_FORCE_ACCESS_CHECK, // Options
  2044. transaction->TreeConnect->Share
  2045. );
  2046. }
  2047. if ( NT_SUCCESS(status) ) {
  2048. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 21, 0 );
  2049. }
  2050. else {
  2051. SrvSetSmbError( WorkContext, status );
  2052. smbStatus = SmbTransStatusErrorWithoutData;
  2053. goto Cleanup;
  2054. }
  2055. if ( !isUnicode ) {
  2056. RtlFreeUnicodeString( &objectName );
  2057. }
  2058. //
  2059. // Save a copy of the file handle for the restart routine.
  2060. //
  2061. WorkContext->Parameters2.FileInformation.FileHandle = fileHandle;
  2062. ASSERT( status != STATUS_OPLOCK_BREAK_IN_PROGRESS );
  2063. smbStatus = GenerateQueryPathInfoResponse( WorkContext, status );
  2064. Cleanup:
  2065. SrvWmiEndContext(WorkContext);
  2066. return smbStatus;
  2067. } // SrvSmbQueryPathInformation
  2068. SMB_TRANS_STATUS
  2069. GenerateQueryPathInfoResponse (
  2070. IN PWORK_CONTEXT WorkContext,
  2071. IN NTSTATUS OpenStatus
  2072. )
  2073. /*++
  2074. Routine Description:
  2075. This function completes processing for and generates a response to a
  2076. query path information response SMB.
  2077. Arguments:
  2078. WorkContext - A pointer to the work context block for this SMB
  2079. OpenStatus - The completion status of the open.
  2080. Return Value:
  2081. The status of the SMB processing.
  2082. --*/
  2083. {
  2084. PREQ_QUERY_PATH_INFORMATION request;
  2085. PRESP_QUERY_PATH_INFORMATION response;
  2086. PTRANSACTION transaction;
  2087. NTSTATUS status;
  2088. BOOLEAN error;
  2089. HANDLE fileHandle;
  2090. USHORT informationLevel;
  2091. PFILE_OBJECT fileObject;
  2092. OBJECT_HANDLE_INFORMATION handleInformation;
  2093. PAGED_CODE( );
  2094. transaction = WorkContext->Parameters.Transaction;
  2095. IF_SMB_DEBUG(QUERY_SET1) {
  2096. KdPrint(( "Query Path Information entered; transaction 0x%p\n",
  2097. transaction ));
  2098. }
  2099. request = (PREQ_QUERY_PATH_INFORMATION)transaction->InParameters;
  2100. response = (PRESP_QUERY_PATH_INFORMATION)transaction->OutParameters;
  2101. fileHandle = WorkContext->Parameters2.FileInformation.FileHandle;
  2102. //
  2103. // If the user didn't have this permission, update the
  2104. // statistics database.
  2105. //
  2106. if ( OpenStatus == STATUS_ACCESS_DENIED ) {
  2107. SrvStatistics.AccessPermissionErrors++;
  2108. }
  2109. if ( !NT_SUCCESS( OpenStatus ) ) {
  2110. IF_DEBUG(ERRORS) {
  2111. KdPrint(( "GenerateQueryPathInfoResponse: SrvIoCreateFile failed: %X\n", OpenStatus ));
  2112. }
  2113. SrvSetSmbError( WorkContext, OpenStatus );
  2114. return SmbTransStatusErrorWithoutData;
  2115. }
  2116. IF_SMB_DEBUG(QUERY_SET2) {
  2117. KdPrint(( "SrvIoCreateFile succeeded, handle = 0x%p\n", fileHandle ));
  2118. }
  2119. //
  2120. // Find out the access the user has.
  2121. //
  2122. status = ObReferenceObjectByHandle(
  2123. fileHandle,
  2124. 0,
  2125. NULL,
  2126. KernelMode,
  2127. (PVOID *)&fileObject,
  2128. &handleInformation
  2129. );
  2130. if ( !NT_SUCCESS(status) ) {
  2131. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  2132. //
  2133. // This internal error bugchecks the system.
  2134. //
  2135. INTERNAL_ERROR(
  2136. ERROR_LEVEL_IMPOSSIBLE,
  2137. "GenerateQueryPathInfoResponse: unable to reference file handle 0x%lx",
  2138. fileHandle,
  2139. NULL
  2140. );
  2141. SrvSetSmbError( WorkContext, OpenStatus );
  2142. return SmbTransStatusErrorWithoutData;
  2143. }
  2144. ObDereferenceObject( fileObject );
  2145. //
  2146. // Verify the information level and the number of input and output
  2147. // data bytes available.
  2148. //
  2149. informationLevel = SmbGetUshort( &request->InformationLevel );
  2150. error = FALSE;
  2151. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  2152. switch ( informationLevel ) {
  2153. case SMB_INFO_STANDARD:
  2154. if ( transaction->MaxDataCount < 22 ) {
  2155. IF_SMB_DEBUG(QUERY_SET1) {
  2156. KdPrint(( "GenerateQueryPathInfoResponse: invalid "
  2157. "MaxDataCount %ld\n", transaction->MaxDataCount ));
  2158. }
  2159. error = TRUE;
  2160. }
  2161. break;
  2162. case SMB_INFO_QUERY_EA_SIZE:
  2163. if ( transaction->MaxDataCount < 26 ) {
  2164. IF_DEBUG(SMB_ERRORS) {
  2165. KdPrint(( "GenerateQueryPathInfoResponse: invalid "
  2166. "MaxDataCount %ld\n", transaction->MaxDataCount ));
  2167. }
  2168. error = TRUE;
  2169. }
  2170. break;
  2171. case SMB_INFO_QUERY_EAS_FROM_LIST:
  2172. case SMB_INFO_QUERY_ALL_EAS:
  2173. if ( transaction->MaxDataCount < 4 ) {
  2174. IF_DEBUG(SMB_ERRORS) {
  2175. KdPrint(( "GenerateQueryPathInfoResponse: invalid "
  2176. "MaxDataCount %ld\n", transaction->MaxDataCount ));
  2177. }
  2178. error = TRUE;
  2179. }
  2180. break;
  2181. case SMB_INFO_IS_NAME_VALID:
  2182. break;
  2183. case SMB_QUERY_FILE_BASIC_INFO:
  2184. CHECK_FILE_INFORMATION_ACCESS(
  2185. handleInformation.GrantedAccess,
  2186. IRP_MJ_QUERY_INFORMATION,
  2187. FileBasicInformation,
  2188. &status
  2189. );
  2190. IF_DEBUG(ERRORS) {
  2191. if ( !NT_SUCCESS(status) ) {
  2192. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2193. "failed: 0x%X, GrantedAccess: %lx\n",
  2194. status, handleInformation.GrantedAccess ));
  2195. }
  2196. }
  2197. break;
  2198. case SMB_QUERY_FILE_STANDARD_INFO:
  2199. CHECK_FILE_INFORMATION_ACCESS(
  2200. handleInformation.GrantedAccess,
  2201. IRP_MJ_QUERY_INFORMATION,
  2202. FileStandardInformation,
  2203. &status
  2204. );
  2205. IF_DEBUG(ERRORS) {
  2206. if ( !NT_SUCCESS(status) ) {
  2207. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2208. "failed: 0x%X, GrantedAccess: %lx\n",
  2209. status, handleInformation.GrantedAccess ));
  2210. }
  2211. }
  2212. break;
  2213. case SMB_QUERY_FILE_EA_INFO:
  2214. CHECK_FILE_INFORMATION_ACCESS(
  2215. handleInformation.GrantedAccess,
  2216. IRP_MJ_QUERY_INFORMATION,
  2217. FileEaInformation,
  2218. &status
  2219. );
  2220. IF_DEBUG(ERRORS) {
  2221. if ( !NT_SUCCESS(status) ) {
  2222. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2223. "failed: 0x%X, GrantedAccess: %lx\n",
  2224. status, handleInformation.GrantedAccess ));
  2225. }
  2226. }
  2227. break;
  2228. case SMB_QUERY_FILE_NAME_INFO:
  2229. CHECK_FILE_INFORMATION_ACCESS(
  2230. handleInformation.GrantedAccess,
  2231. IRP_MJ_QUERY_INFORMATION,
  2232. FileNameInformation,
  2233. &status
  2234. );
  2235. IF_DEBUG(ERRORS) {
  2236. if ( !NT_SUCCESS(status) ) {
  2237. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2238. "failed: 0x%X, GrantedAccess: %lx\n",
  2239. status, handleInformation.GrantedAccess ));
  2240. }
  2241. }
  2242. break;
  2243. case SMB_QUERY_FILE_ALL_INFO:
  2244. CHECK_FILE_INFORMATION_ACCESS(
  2245. handleInformation.GrantedAccess,
  2246. IRP_MJ_QUERY_INFORMATION,
  2247. FileAllInformation,
  2248. &status
  2249. );
  2250. IF_DEBUG(ERRORS) {
  2251. if ( !NT_SUCCESS(status) ) {
  2252. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2253. "failed: 0x%X, GrantedAccess: %lx\n",
  2254. status, handleInformation.GrantedAccess ));
  2255. }
  2256. }
  2257. break;
  2258. case SMB_QUERY_FILE_ALT_NAME_INFO:
  2259. CHECK_FILE_INFORMATION_ACCESS(
  2260. handleInformation.GrantedAccess,
  2261. IRP_MJ_QUERY_INFORMATION,
  2262. FileAlternateNameInformation,
  2263. &status
  2264. );
  2265. IF_DEBUG(ERRORS) {
  2266. if ( !NT_SUCCESS(status) ) {
  2267. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2268. "failed: 0x%X, GrantedAccess: %lx\n",
  2269. status, handleInformation.GrantedAccess ));
  2270. }
  2271. }
  2272. break;
  2273. case SMB_QUERY_FILE_STREAM_INFO:
  2274. CHECK_FILE_INFORMATION_ACCESS(
  2275. handleInformation.GrantedAccess,
  2276. IRP_MJ_QUERY_INFORMATION,
  2277. FileStreamInformation,
  2278. &status
  2279. );
  2280. IF_DEBUG(ERRORS) {
  2281. if ( !NT_SUCCESS(status) ) {
  2282. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2283. "failed: 0x%X, GrantedAccess: %lx\n",
  2284. status, handleInformation.GrantedAccess ));
  2285. }
  2286. }
  2287. break;
  2288. case SMB_QUERY_FILE_COMPRESSION_INFO:
  2289. CHECK_FILE_INFORMATION_ACCESS(
  2290. handleInformation.GrantedAccess,
  2291. IRP_MJ_QUERY_INFORMATION,
  2292. FileCompressionInformation,
  2293. &status
  2294. );
  2295. IF_DEBUG(ERRORS) {
  2296. if ( !NT_SUCCESS(status) ) {
  2297. KdPrint(( "SrvSmbQueryFileInformation: IoCheckFunctionAccess "
  2298. "failed: 0x%X, GrantedAccess: %lx\n",
  2299. status, handleInformation.GrantedAccess ));
  2300. }
  2301. }
  2302. break;
  2303. default:
  2304. IF_DEBUG(SMB_ERRORS) {
  2305. KdPrint(( "GenerateQueryPathInfoResponse: invalid info level"
  2306. "%ld\n", informationLevel ));
  2307. }
  2308. error = TRUE;
  2309. break;
  2310. }
  2311. } else {
  2312. if( informationLevel - SMB_INFO_PASSTHROUGH >= FileMaximumInformation ) {
  2313. status = STATUS_INVALID_INFO_CLASS;
  2314. }
  2315. if( NT_SUCCESS( status ) ) {
  2316. status = IoCheckQuerySetFileInformation( informationLevel - SMB_INFO_PASSTHROUGH,
  2317. 0xFFFFFFFF,
  2318. FALSE
  2319. );
  2320. }
  2321. if( NT_SUCCESS( status ) ) {
  2322. CHECK_FILE_INFORMATION_ACCESS(
  2323. handleInformation.GrantedAccess,
  2324. IRP_MJ_QUERY_INFORMATION,
  2325. informationLevel - SMB_INFO_PASSTHROUGH,
  2326. &status
  2327. );
  2328. } else {
  2329. error = TRUE;
  2330. }
  2331. }
  2332. if ( error ) {
  2333. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 32, 0 );
  2334. SrvNtClose( fileHandle, TRUE );
  2335. SrvSetSmbError( WorkContext, STATUS_OS2_INVALID_LEVEL );
  2336. return SmbTransStatusErrorWithoutData;
  2337. }
  2338. //
  2339. // Get the necessary information about the file.
  2340. //
  2341. status = QueryPathOrFileInformation(
  2342. WorkContext,
  2343. transaction,
  2344. informationLevel,
  2345. fileHandle,
  2346. (PRESP_QUERY_PATH_INFORMATION)response
  2347. );
  2348. //
  2349. // Map STATUS_BUFFER_OVERFLOW for OS/2 clients.
  2350. //
  2351. if ( status == STATUS_BUFFER_OVERFLOW &&
  2352. !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  2353. status = STATUS_BUFFER_TOO_SMALL;
  2354. }
  2355. //
  2356. // Close the file--it was only opened to read the attributes.
  2357. //
  2358. if ( informationLevel != SMB_INFO_IS_NAME_VALID ) {
  2359. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 33, 0 );
  2360. SrvNtClose( fileHandle, TRUE );
  2361. }
  2362. //
  2363. // If an error occurred, return an appropriate response.
  2364. //
  2365. if ( !NT_SUCCESS(status) ) {
  2366. //
  2367. // QueryPathOrFileInformation already set the response parameters,
  2368. // so just return an error condition.
  2369. //
  2370. SrvSetSmbError2( WorkContext, status, TRUE );
  2371. return SmbTransStatusErrorWithData;
  2372. }
  2373. IF_DEBUG(TRACE2) KdPrint(( "GenerateQueryPathInfoResponse complete.\n" ));
  2374. return SmbTransStatusSuccess;
  2375. } // GenerateQueryPathInfoResponse
  2376. STATIC
  2377. NTSTATUS
  2378. SetPathOrFileInformation (
  2379. IN PWORK_CONTEXT WorkContext,
  2380. IN PTRANSACTION Transaction,
  2381. IN USHORT InformationLevel,
  2382. IN HANDLE FileHandle,
  2383. OUT PRESP_SET_PATH_INFORMATION Response
  2384. )
  2385. {
  2386. NTSTATUS status = STATUS_SUCCESS;
  2387. IO_STATUS_BLOCK ioStatusBlock;
  2388. SMB_DATE date;
  2389. SMB_TIME time;
  2390. PWCHAR p, ep;
  2391. PFILESTATUS fileStatus = (PFILESTATUS)Transaction->InData;
  2392. FILE_BASIC_INFORMATION fileBasicInformation;
  2393. USHORT eaErrorOffset;
  2394. PAGED_CODE( );
  2395. if( InformationLevel < SMB_INFO_PASSTHROUGH ) {
  2396. switch( InformationLevel ) {
  2397. case SMB_INFO_STANDARD:
  2398. //
  2399. // Information level is STANDARD. Set normal file information.
  2400. // Convert the DOS dates and times passed in the SMB to NT TIMEs
  2401. // to pass to NtSetInformationFile. Note that we zero the rest
  2402. // of the fileBasicInformation structure so that the corresponding
  2403. // fields are not changed. Note also that the file attributes
  2404. // are not changed.
  2405. //
  2406. RtlZeroMemory( &fileBasicInformation, sizeof(fileBasicInformation) );
  2407. if ( !SmbIsDateZero(&fileStatus->CreationDate) ||
  2408. !SmbIsTimeZero(&fileStatus->CreationTime) ) {
  2409. SmbMoveDate( &date, &fileStatus->CreationDate );
  2410. SmbMoveTime( &time, &fileStatus->CreationTime );
  2411. SrvDosTimeToTime( &fileBasicInformation.CreationTime, date, time );
  2412. }
  2413. if ( !SmbIsDateZero(&fileStatus->LastAccessDate) ||
  2414. !SmbIsTimeZero(&fileStatus->LastAccessTime) ) {
  2415. SmbMoveDate( &date, &fileStatus->LastAccessDate );
  2416. SmbMoveTime( &time, &fileStatus->LastAccessTime );
  2417. SrvDosTimeToTime( &fileBasicInformation.LastAccessTime, date, time );
  2418. }
  2419. if ( !SmbIsDateZero(&fileStatus->LastWriteDate) ||
  2420. !SmbIsTimeZero(&fileStatus->LastWriteTime) ) {
  2421. SmbMoveDate( &date, &fileStatus->LastWriteDate );
  2422. SmbMoveTime( &time, &fileStatus->LastWriteTime );
  2423. SrvDosTimeToTime( &fileBasicInformation.LastWriteTime, date, time );
  2424. }
  2425. //
  2426. // Call NtSetInformationFile to set the information from the SMB.
  2427. //
  2428. status = NtSetInformationFile(
  2429. FileHandle,
  2430. &ioStatusBlock,
  2431. &fileBasicInformation,
  2432. sizeof(FILE_BASIC_INFORMATION),
  2433. FileBasicInformation
  2434. );
  2435. if ( !NT_SUCCESS(status) ) {
  2436. INTERNAL_ERROR(
  2437. ERROR_LEVEL_UNEXPECTED,
  2438. "SetPathOrFileInformation: SrvSetInformationFile returned: %X",
  2439. status,
  2440. NULL
  2441. );
  2442. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  2443. }
  2444. //
  2445. // No EAs to deal with. Set EA error offset to zero.
  2446. //
  2447. SmbPutUshort( &Response->EaErrorOffset, 0 );
  2448. break;
  2449. case SMB_INFO_QUERY_EA_SIZE:
  2450. //
  2451. // The request is to set the file's EAs.
  2452. //
  2453. status = SrvSetOs2FeaList(
  2454. FileHandle,
  2455. (PFEALIST)Transaction->InData,
  2456. Transaction->DataCount,
  2457. &eaErrorOffset
  2458. );
  2459. if ( !NT_SUCCESS(status) ) {
  2460. IF_DEBUG(ERRORS) {
  2461. KdPrint(( "SetPathOrFileInformation: SrvSetOs2FeaList "
  2462. "failed: %X\n", status ));
  2463. }
  2464. }
  2465. //
  2466. // Return the EA error offset in the response.
  2467. //
  2468. SmbPutUshort( &Response->EaErrorOffset, eaErrorOffset );
  2469. break;
  2470. case SMB_SET_FILE_BASIC_INFO:
  2471. case SMB_SET_FILE_DISPOSITION_INFO:
  2472. case SMB_SET_FILE_ALLOCATION_INFO:
  2473. case SMB_SET_FILE_END_OF_FILE_INFO:
  2474. //
  2475. // The data buffer is in NT format. Pass it directly to the
  2476. // filesystem.
  2477. //
  2478. if( Transaction->DataCount <
  2479. MAP_SMB_INFO_TO_MIN_NT_SIZE(SetFileInformationSize, InformationLevel ) ) {
  2480. //
  2481. // The buffer is too small. Return an error.
  2482. //
  2483. status = STATUS_INFO_LENGTH_MISMATCH;
  2484. } else {
  2485. status = NtSetInformationFile(
  2486. FileHandle,
  2487. &ioStatusBlock,
  2488. Transaction->InData,
  2489. Transaction->DataCount,
  2490. MAP_SMB_INFO_TYPE_TO_NT(
  2491. SetFileInformation,
  2492. InformationLevel
  2493. )
  2494. );
  2495. }
  2496. //
  2497. // No EAs to deal with. Set EA error offset to zero.
  2498. //
  2499. SmbPutUshort( &Response->EaErrorOffset, 0 );
  2500. break;
  2501. default:
  2502. status = STATUS_OS2_INVALID_LEVEL;
  2503. break;
  2504. }
  2505. } else {
  2506. PFILE_RENAME_INFORMATION setInfo = NULL;
  2507. ULONG setInfoLength;
  2508. #ifdef _WIN64
  2509. PFILE_RENAME_INFORMATION32 pRemoteInfo;
  2510. #endif
  2511. InformationLevel -= SMB_INFO_PASSTHROUGH;
  2512. setInfo = (PFILE_RENAME_INFORMATION)Transaction->InData;
  2513. setInfoLength = Transaction->DataCount;
  2514. //
  2515. // There are some info levels which we do not allow in this path. Unless we
  2516. // put in special handling, we can not allow any that pass handles. And we
  2517. // would need to be careful on any that allow renaming or linking (to prevent
  2518. // escaping the share). These are the ones we restrict or disallow,
  2519. // which the I/O subsystem may otherwise allow:
  2520. //
  2521. switch( InformationLevel ) {
  2522. case FileLinkInformation:
  2523. case FileMoveClusterInformation:
  2524. case FileTrackingInformation:
  2525. case FileCompletionInformation:
  2526. case FileMailslotSetInformation:
  2527. status = STATUS_NOT_SUPPORTED;
  2528. break;
  2529. case FileRenameInformation: {
  2530. PWCHAR s, es;
  2531. #ifdef _WIN64
  2532. pRemoteInfo = (PFILE_RENAME_INFORMATION32)Transaction->InData;
  2533. setInfoLength = Transaction->DataCount + sizeof(PVOID)-sizeof(ULONG);
  2534. setInfo = (PFILE_RENAME_INFORMATION)ALLOCATE_NONPAGED_POOL( setInfoLength, BlockTypeMisc );
  2535. if( !setInfo )
  2536. {
  2537. status = STATUS_INSUFFICIENT_RESOURCES;
  2538. break;
  2539. }
  2540. // Thunk most of the structure but wait to copy until we validate the file
  2541. // name length is correct
  2542. setInfo->ReplaceIfExists = pRemoteInfo->ReplaceIfExists;
  2543. setInfo->RootDirectory = UlongToHandle( pRemoteInfo->RootDirectory );
  2544. setInfo->FileNameLength = pRemoteInfo->FileNameLength;
  2545. #endif
  2546. //
  2547. // See if the structure is internally consistent
  2548. //
  2549. if( setInfoLength < sizeof( FILE_RENAME_INFORMATION ) ||
  2550. setInfo->RootDirectory != NULL ||
  2551. setInfo->FileNameLength > setInfoLength ||
  2552. (setInfo->FileNameLength & (sizeof(WCHAR)-1)) ||
  2553. setInfo->FileNameLength +
  2554. FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName ) >
  2555. setInfoLength ) {
  2556. status = STATUS_INVALID_PARAMETER;
  2557. break;
  2558. }
  2559. #ifdef _WIN64
  2560. // We've validated the original buffer, so lets copy the filename
  2561. RtlCopyMemory( setInfo->FileName, pRemoteInfo->FileName, setInfo->FileNameLength );
  2562. #endif
  2563. //
  2564. // If there are any path separaters in the name, then we do not support
  2565. // this operation.
  2566. //
  2567. es = &setInfo->FileName[ setInfo->FileNameLength / sizeof( WCHAR ) ];
  2568. for( s = setInfo->FileName; s < es; s++ ) {
  2569. if( IS_UNICODE_PATH_SEPARATOR( *s ) ) {
  2570. status = STATUS_NOT_SUPPORTED;
  2571. break;
  2572. }
  2573. }
  2574. }
  2575. }
  2576. if( NT_SUCCESS( status ) ) {
  2577. //
  2578. // See if the supplied parameters are correct.
  2579. //
  2580. status = IoCheckQuerySetFileInformation( InformationLevel,
  2581. setInfoLength,
  2582. TRUE
  2583. );
  2584. if( NT_SUCCESS( status ) ) {
  2585. //
  2586. // Some information levels require us to impersonate the client.
  2587. //
  2588. status = IMPERSONATE( WorkContext );
  2589. if( NT_SUCCESS( status ) ) {
  2590. status = NtSetInformationFile(
  2591. FileHandle,
  2592. &ioStatusBlock,
  2593. setInfo,
  2594. setInfoLength,
  2595. InformationLevel
  2596. );
  2597. REVERT();
  2598. //
  2599. // No EAs to deal with. Set EA error offset to zero.
  2600. //
  2601. SmbPutUshort( &Response->EaErrorOffset, 0 );
  2602. }
  2603. }
  2604. }
  2605. #ifdef _WIN64
  2606. if( (FileRenameInformation == InformationLevel) && setInfo )
  2607. {
  2608. DEALLOCATE_NONPAGED_POOL( setInfo );
  2609. setInfo = NULL;
  2610. }
  2611. #endif
  2612. }
  2613. //
  2614. // Build the output parameter and data structures. It is basically
  2615. // the same for all info levels reguardless of the completion status.
  2616. //
  2617. Transaction->SetupCount = 0;
  2618. Transaction->ParameterCount = 2;
  2619. Transaction->DataCount = 0;
  2620. return status;
  2621. } // SetPathOrFileInformation
  2622. SMB_TRANS_STATUS
  2623. SrvSmbSetFileInformation (
  2624. IN OUT PWORK_CONTEXT WorkContext
  2625. )
  2626. /*++
  2627. Routine Description:
  2628. Processes the Set File Information request. This request arrives
  2629. in a Transaction2 SMB. Set File Information corresponds to the
  2630. OS/2 DosSetFileInfo service.
  2631. Arguments:
  2632. WorkContext - Supplies the address of a Work Context Block
  2633. describing the current request. See smbtypes.h for a more
  2634. complete description of the valid fields.
  2635. Return Value:
  2636. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  2637. whether data should be returned to the client. See smbtypes.h
  2638. for a more complete description.
  2639. --*/
  2640. {
  2641. PREQ_SET_FILE_INFORMATION request;
  2642. PRESP_SET_FILE_INFORMATION response;
  2643. NTSTATUS status = STATUS_SUCCESS;
  2644. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  2645. PTRANSACTION transaction;
  2646. PRFCB rfcb;
  2647. USHORT informationLevel;
  2648. USHORT NtInformationLevel;
  2649. ACCESS_MASK grantedAccess;
  2650. PAGED_CODE( );
  2651. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2652. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SET_FILE_INFORMATION;
  2653. SrvWmiStartContext(WorkContext);
  2654. transaction = WorkContext->Parameters.Transaction;
  2655. IF_SMB_DEBUG(QUERY_SET1) {
  2656. KdPrint(( "Set File Information entered; transaction 0x%p\n",
  2657. transaction ));
  2658. }
  2659. request = (PREQ_SET_FILE_INFORMATION)transaction->InParameters;
  2660. response = (PRESP_SET_FILE_INFORMATION)transaction->OutParameters;
  2661. //
  2662. // Verify that enough parameter bytes were sent and that we're allowed
  2663. // to return enough parameter bytes.
  2664. //
  2665. if ( (transaction->ParameterCount <
  2666. sizeof(REQ_SET_FILE_INFORMATION)) ||
  2667. (transaction->MaxParameterCount <
  2668. sizeof(RESP_SET_FILE_INFORMATION)) ) {
  2669. //
  2670. // Not enough parameter bytes were sent.
  2671. //
  2672. IF_DEBUG(SMB_ERRORS) {
  2673. KdPrint(( "SrvSmbSetFileInformation: bad parameter byte counts: "
  2674. "%ld %ld\n",
  2675. transaction->ParameterCount,
  2676. transaction->MaxParameterCount ));
  2677. }
  2678. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2679. status = STATUS_INVALID_SMB;
  2680. SmbStatus = SmbTransStatusErrorWithoutData;
  2681. goto Cleanup;
  2682. }
  2683. //
  2684. // Verify the FID. If verified, the RFCB block is referenced
  2685. // and its addresses is stored in the WorkContext block, and the
  2686. // RFCB address is returned.
  2687. //
  2688. rfcb = SrvVerifyFid(
  2689. WorkContext,
  2690. SmbGetUshort( &request->Fid ),
  2691. TRUE,
  2692. SrvRestartExecuteTransaction, // serialize with raw write
  2693. &status
  2694. );
  2695. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  2696. if ( !NT_SUCCESS( status ) ) {
  2697. //
  2698. // Invalid file ID or write behind error. Reject the request.
  2699. //
  2700. IF_DEBUG(ERRORS) {
  2701. KdPrint((
  2702. "SrvSmbSetFileInformation: Status %X on FID: 0x%lx\n",
  2703. status,
  2704. SmbGetUshort( &request->Fid )
  2705. ));
  2706. }
  2707. SrvSetSmbError( WorkContext, status );
  2708. SmbStatus = SmbTransStatusErrorWithoutData;
  2709. goto Cleanup;
  2710. }
  2711. //
  2712. // The work item has been queued because a raw write is in
  2713. // progress.
  2714. //
  2715. SmbStatus = SmbTransStatusInProgress;
  2716. goto Cleanup;
  2717. }
  2718. //
  2719. // Verify the information level and the number of input and output
  2720. // data bytes available.
  2721. //
  2722. informationLevel = SmbGetUshort( &request->InformationLevel );
  2723. grantedAccess = rfcb->GrantedAccess;
  2724. status = STATUS_SUCCESS;
  2725. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  2726. switch ( informationLevel ) {
  2727. case SMB_INFO_STANDARD:
  2728. if ( transaction->DataCount < 22 ) {
  2729. IF_DEBUG(SMB_ERRORS) {
  2730. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2731. transaction->DataCount ));
  2732. }
  2733. status = STATUS_INVALID_SMB;
  2734. }
  2735. //
  2736. // Verify that the client has write attributes access to the
  2737. // file via the specified handle.
  2738. //
  2739. CHECK_FILE_INFORMATION_ACCESS(
  2740. grantedAccess,
  2741. IRP_MJ_SET_INFORMATION,
  2742. FileBasicInformation,
  2743. &status
  2744. );
  2745. IF_DEBUG(ERRORS) {
  2746. if ( !NT_SUCCESS(status) ) {
  2747. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2748. "failed: 0x%X, GrantedAccess: %lx\n",
  2749. status, grantedAccess ));
  2750. }
  2751. }
  2752. break;
  2753. case SMB_INFO_QUERY_EA_SIZE:
  2754. if ( transaction->DataCount < 4 ) {
  2755. IF_DEBUG(SMB_ERRORS) {
  2756. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2757. transaction->MaxParameterCount ));
  2758. }
  2759. status = STATUS_INVALID_SMB;
  2760. }
  2761. //
  2762. // Verify that the client has write EA access to the file via
  2763. // the specified handle.
  2764. //
  2765. CHECK_FUNCTION_ACCESS(
  2766. grantedAccess,
  2767. IRP_MJ_SET_EA,
  2768. 0,
  2769. 0,
  2770. &status
  2771. );
  2772. IF_DEBUG(ERRORS) {
  2773. if ( !NT_SUCCESS(status) ) {
  2774. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2775. "failed: 0x%X, GrantedAccess: %lx\n",
  2776. status, grantedAccess ));
  2777. }
  2778. }
  2779. break;
  2780. case SMB_SET_FILE_BASIC_INFO:
  2781. if ( transaction->DataCount != sizeof( FILE_BASIC_INFORMATION ) ) {
  2782. IF_DEBUG(SMB_ERRORS) {
  2783. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2784. transaction->DataCount ));
  2785. }
  2786. status = STATUS_INVALID_SMB;
  2787. }
  2788. //
  2789. // Verify that the client has write attributes access to the
  2790. // file via the specified handle.
  2791. //
  2792. CHECK_FILE_INFORMATION_ACCESS(
  2793. grantedAccess,
  2794. IRP_MJ_SET_INFORMATION,
  2795. FileBasicInformation,
  2796. &status
  2797. );
  2798. IF_DEBUG(ERRORS) {
  2799. if ( !NT_SUCCESS(status) ) {
  2800. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2801. "failed: 0x%X, GrantedAccess: %lx\n",
  2802. status, grantedAccess ));
  2803. }
  2804. }
  2805. break;
  2806. #if 0 // No longer supported
  2807. case SMB_SET_FILE_RENAME_INFO:
  2808. //
  2809. // The data must contain rename information plus a non-zero
  2810. // length name.
  2811. //
  2812. if ( transaction->DataCount <=
  2813. FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName ) ) {
  2814. IF_DEBUG(SMB_ERRORS) {
  2815. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2816. transaction->DataCount ));
  2817. }
  2818. status = STATUS_INVALID_SMB;
  2819. }
  2820. //
  2821. // Verify that the client has write attributes access to the
  2822. // file via the specified handle.
  2823. //
  2824. CHECK_FILE_INFORMATION_ACCESS(
  2825. grantedAccess,
  2826. IRP_MJ_SET_INFORMATION,
  2827. FileRenameInformation,
  2828. &status
  2829. );
  2830. IF_DEBUG(ERRORS) {
  2831. if ( !NT_SUCCESS(status) ) {
  2832. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2833. "failed: 0x%X, GrantedAccess: %lx\n",
  2834. status, grantedAccess ));
  2835. }
  2836. }
  2837. break;
  2838. #endif
  2839. case SMB_SET_FILE_DISPOSITION_INFO:
  2840. if ( transaction->DataCount !=
  2841. sizeof( FILE_DISPOSITION_INFORMATION ) ){
  2842. IF_DEBUG(SMB_ERRORS) {
  2843. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2844. transaction->DataCount ));
  2845. }
  2846. status = STATUS_INVALID_SMB;
  2847. }
  2848. //
  2849. // Verify that the client has write attributes access to the
  2850. // file via the specified handle.
  2851. //
  2852. CHECK_FILE_INFORMATION_ACCESS(
  2853. grantedAccess,
  2854. IRP_MJ_SET_INFORMATION,
  2855. FileDispositionInformation,
  2856. &status
  2857. );
  2858. IF_DEBUG(ERRORS) {
  2859. if ( !NT_SUCCESS(status) ) {
  2860. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2861. "failed: 0x%X, GrantedAccess: %lx\n",
  2862. status, grantedAccess ));
  2863. }
  2864. }
  2865. break;
  2866. case SMB_SET_FILE_ALLOCATION_INFO:
  2867. if ( transaction->DataCount !=
  2868. sizeof( FILE_ALLOCATION_INFORMATION ) ){
  2869. IF_DEBUG(SMB_ERRORS) {
  2870. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2871. transaction->DataCount ));
  2872. }
  2873. status = STATUS_INVALID_SMB;
  2874. }
  2875. //
  2876. // Verify that the client has write attributes access to the
  2877. // file via the specified handle.
  2878. //
  2879. CHECK_FILE_INFORMATION_ACCESS(
  2880. grantedAccess,
  2881. IRP_MJ_SET_INFORMATION,
  2882. FileAllocationInformation,
  2883. &status
  2884. );
  2885. IF_DEBUG(ERRORS) {
  2886. if ( !NT_SUCCESS(status) ) {
  2887. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2888. "failed: 0x%X, GrantedAccess: %lx\n",
  2889. status, grantedAccess ));
  2890. }
  2891. }
  2892. break;
  2893. case SMB_SET_FILE_END_OF_FILE_INFO:
  2894. if ( transaction->DataCount !=
  2895. sizeof( FILE_END_OF_FILE_INFORMATION ) ){
  2896. IF_DEBUG(SMB_ERRORS) {
  2897. KdPrint(( "SrvSmbSetFileInformation: invalid DataCount %ld\n",
  2898. transaction->DataCount ));
  2899. }
  2900. status = STATUS_INVALID_SMB;
  2901. }
  2902. //
  2903. // Verify that the client has write attributes access to the
  2904. // file via the specified handle.
  2905. //
  2906. CHECK_FILE_INFORMATION_ACCESS(
  2907. grantedAccess,
  2908. IRP_MJ_SET_INFORMATION,
  2909. FileEndOfFileInformation,
  2910. &status
  2911. );
  2912. IF_DEBUG(ERRORS) {
  2913. if ( !NT_SUCCESS(status) ) {
  2914. KdPrint(( "SrvSmbSetFileInformation: IoCheckFunctionAccess "
  2915. "failed: 0x%X, GrantedAccess: %lx\n",
  2916. status, grantedAccess ));
  2917. }
  2918. }
  2919. break;
  2920. default:
  2921. IF_DEBUG(SMB_ERRORS) {
  2922. KdPrint(( "SrvSmbSetFileInformation: invalid info level %ld\n",
  2923. informationLevel ));
  2924. }
  2925. status = STATUS_OS2_INVALID_LEVEL;
  2926. }
  2927. } else {
  2928. if( informationLevel - SMB_INFO_PASSTHROUGH >= FileMaximumInformation ) {
  2929. status = STATUS_INVALID_INFO_CLASS;
  2930. } else {
  2931. CHECK_FILE_INFORMATION_ACCESS(
  2932. grantedAccess,
  2933. IRP_MJ_SET_INFORMATION,
  2934. informationLevel - SMB_INFO_PASSTHROUGH,
  2935. &status
  2936. );
  2937. }
  2938. IF_DEBUG(ERRORS) {
  2939. if ( !NT_SUCCESS(status) ) {
  2940. KdPrint(( "SrvSmbSetFileInformation level %u: IoCheckFunctionAccess "
  2941. "failed: 0x%X, GrantedAccess: %lx\n",
  2942. informationLevel, status, grantedAccess ));
  2943. }
  2944. }
  2945. }
  2946. if ( !NT_SUCCESS(status) ) {
  2947. SrvSetSmbError( WorkContext, status );
  2948. SmbStatus = SmbTransStatusErrorWithoutData;
  2949. goto Cleanup;
  2950. }
  2951. //
  2952. // Set the appropriate information about the file.
  2953. //
  2954. status = SetPathOrFileInformation(
  2955. WorkContext,
  2956. transaction,
  2957. informationLevel,
  2958. rfcb->Lfcb->FileHandle,
  2959. (PRESP_SET_PATH_INFORMATION)response
  2960. );
  2961. //
  2962. // If an error occurred, return an appropriate response.
  2963. //
  2964. if ( !NT_SUCCESS(status) ) {
  2965. //
  2966. // SetPathOrFileInformation already set the response parameters,
  2967. // so just return an error condition.
  2968. //
  2969. SrvSetSmbError2( WorkContext, status, TRUE );
  2970. SmbStatus = SmbTransStatusErrorWithData;
  2971. goto Cleanup;
  2972. }
  2973. #ifdef INCLUDE_SMB_IFMODIFIED
  2974. rfcb->Lfcb->FileUpdated = TRUE;
  2975. #endif
  2976. //
  2977. // reset this boolean so that the rfcb will not be cached after client close
  2978. //
  2979. rfcb->IsCacheable = FALSE;
  2980. SmbStatus = SmbTransStatusSuccess;
  2981. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSetFileInformation complete.\n" ));
  2982. Cleanup:
  2983. SrvWmiEndContext(WorkContext);
  2984. return SmbStatus;
  2985. } // SrvSmbSetFileInformation
  2986. SMB_TRANS_STATUS
  2987. SrvSmbSetPathInformation (
  2988. IN OUT PWORK_CONTEXT WorkContext
  2989. )
  2990. /*++
  2991. Routine Description:
  2992. Processes the Set Path Information request. This request arrives
  2993. in a Transaction2 SMB. Set Path Information corresponds to the
  2994. OS/2 DosSetPathInfo service.
  2995. Arguments:
  2996. WorkContext - Supplies the address of a Work Context Block
  2997. describing the current request. See smbtypes.h for a more
  2998. complete description of the valid fields.
  2999. Return Value:
  3000. SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
  3001. whether data should be returned to the client. See smbtypes.h
  3002. for a more complete description.
  3003. --*/
  3004. {
  3005. PTRANSACTION transaction;
  3006. PREQ_SET_PATH_INFORMATION request;
  3007. USHORT informationLevel;
  3008. NTSTATUS status = STATUS_SUCCESS;
  3009. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  3010. IO_STATUS_BLOCK ioStatusBlock;
  3011. HANDLE fileHandle;
  3012. OBJECT_ATTRIBUTES objectAttributes;
  3013. UNICODE_STRING objectName;
  3014. BOOLEAN isUnicode;
  3015. ACCESS_MASK desiredAccess;
  3016. PAGED_CODE( );
  3017. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  3018. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SET_PATH_INFORMATION;
  3019. SrvWmiStartContext(WorkContext);
  3020. transaction = WorkContext->Parameters.Transaction;
  3021. IF_SMB_DEBUG(QUERY_SET1) {
  3022. KdPrint(( "SrvSmbSetPathInformation entered; transaction 0x%p\n",
  3023. transaction ));
  3024. }
  3025. request = (PREQ_SET_PATH_INFORMATION)transaction->InParameters;
  3026. informationLevel = SmbGetUshort( &request->InformationLevel );
  3027. switch( informationLevel ) {
  3028. case SMB_SET_FILE_ALLOCATION_INFO:
  3029. case SMB_SET_FILE_END_OF_FILE_INFO:
  3030. desiredAccess = FILE_WRITE_DATA;
  3031. break;
  3032. case SMB_SET_FILE_DISPOSITION_INFO:
  3033. desiredAccess = DELETE;
  3034. break;
  3035. case SMB_INFO_SET_EAS:
  3036. desiredAccess = FILE_WRITE_EA;
  3037. break;
  3038. default:
  3039. desiredAccess = FILE_WRITE_ATTRIBUTES;
  3040. break;
  3041. }
  3042. if( desiredAccess != FILE_WRITE_ATTRIBUTES &&
  3043. WorkContext->UsingBlockingThread == 0 ) {
  3044. //
  3045. // We can't process the SMB in a nonblocking thread because this
  3046. // info level requires opening the file, which may be oplocked, so
  3047. // the open operation may block.
  3048. //
  3049. WorkContext->FspRestartRoutine = SrvRestartExecuteTransaction;
  3050. SrvQueueWorkToBlockingThread( WorkContext );
  3051. SmbStatus = SmbTransStatusInProgress;
  3052. goto Cleanup;
  3053. }
  3054. //
  3055. // Verify that enough parameter bytes were sent and that we're allowed
  3056. // to return enough parameter bytes.
  3057. //
  3058. request = (PREQ_SET_PATH_INFORMATION)transaction->InParameters;
  3059. if ( (transaction->ParameterCount <
  3060. sizeof(REQ_SET_PATH_INFORMATION)) ||
  3061. (transaction->MaxParameterCount <
  3062. sizeof(RESP_SET_PATH_INFORMATION)) ) {
  3063. //
  3064. // Not enough parameter bytes were sent.
  3065. //
  3066. IF_DEBUG(SMB_ERRORS) {
  3067. KdPrint(( "SrvSmbSetPathInformation: bad parameter byte "
  3068. "counts: %ld %ld\n",
  3069. transaction->ParameterCount,
  3070. transaction->MaxParameterCount ));
  3071. }
  3072. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  3073. status = STATUS_INVALID_SMB;
  3074. SmbStatus = SmbTransStatusErrorWithoutData;
  3075. goto Cleanup;
  3076. }
  3077. //
  3078. // Make sure the client is allowed to do this, if we have an Admin share
  3079. //
  3080. status = SrvIsAllowedOnAdminShare( WorkContext, transaction->TreeConnect->Share );
  3081. if( !NT_SUCCESS( status ) ) {
  3082. SrvSetSmbError( WorkContext, status );
  3083. SmbStatus = SmbTransStatusErrorWithoutData;
  3084. goto Cleanup;
  3085. }
  3086. //
  3087. // Get the path name of the file to open relative to the share.
  3088. //
  3089. isUnicode = SMB_IS_UNICODE( WorkContext );
  3090. status = SrvCanonicalizePathName(
  3091. WorkContext,
  3092. transaction->TreeConnect->Share,
  3093. NULL,
  3094. request->Buffer,
  3095. END_OF_TRANSACTION_PARAMETERS( transaction ),
  3096. TRUE,
  3097. isUnicode,
  3098. &objectName
  3099. );
  3100. if( !NT_SUCCESS( status ) ) {
  3101. IF_DEBUG(SMB_ERRORS) {
  3102. KdPrint(( "SrvSmbSetPathInformation: bad path name: %s\n",
  3103. request->Buffer ));
  3104. }
  3105. SrvSetSmbError( WorkContext, status );
  3106. SmbStatus = SmbTransStatusErrorWithoutData;
  3107. goto Cleanup;
  3108. }
  3109. //
  3110. // If the client is trying to operate on the root of the share, reject
  3111. // the request.
  3112. //
  3113. if ( objectName.Length < sizeof(WCHAR) ) {
  3114. IF_DEBUG(SMB_ERRORS) {
  3115. KdPrint(( "SrvSmbSetPathInformation: attempting to set info on "
  3116. "share root\n" ));
  3117. }
  3118. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  3119. status = STATUS_ACCESS_DENIED;
  3120. if ( !isUnicode ) {
  3121. RtlFreeUnicodeString( &objectName );
  3122. }
  3123. SmbStatus = SmbStatusSendResponse;
  3124. goto Cleanup;
  3125. }
  3126. //
  3127. // Initialize the object attributes structure.
  3128. //
  3129. SrvInitializeObjectAttributes_U(
  3130. &objectAttributes,
  3131. &objectName,
  3132. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  3133. transaction->Session->UsingUppercasePaths) ?
  3134. OBJ_CASE_INSENSITIVE : 0L,
  3135. NULL,
  3136. NULL
  3137. );
  3138. IF_SMB_DEBUG(QUERY_SET2) {
  3139. KdPrint(( "Opening file %wZ\n", &objectName ));
  3140. }
  3141. //
  3142. // Open the file -- must be opened in order to have a handle to pass
  3143. // to NtSetInformationFile. We will close it after getting the
  3144. // necessary information.
  3145. //
  3146. // The DosQPathInfo API insures that EAs are written directly to
  3147. // the disk rather than cached, so if EAs are being written, open
  3148. // with FILE_WRITE_THROUGH. See OS/2 1.2 DCR 581 for more
  3149. // information.
  3150. //
  3151. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  3152. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  3153. status = SrvIoCreateFile(
  3154. WorkContext,
  3155. &fileHandle,
  3156. desiredAccess,
  3157. &objectAttributes,
  3158. &ioStatusBlock,
  3159. NULL, // AllocationSize
  3160. 0, // FileAttributes
  3161. FILE_SHARE_READ | FILE_SHARE_WRITE |
  3162. FILE_SHARE_DELETE, // ShareAccess
  3163. FILE_OPEN, // Disposition
  3164. FILE_OPEN_REPARSE_POINT, // CreateOptions
  3165. NULL, // EaBuffer
  3166. 0, // EaLength
  3167. CreateFileTypeNone,
  3168. NULL, // ExtraCreateParameters
  3169. IO_FORCE_ACCESS_CHECK, // Options
  3170. transaction->TreeConnect->Share
  3171. );
  3172. if( status == STATUS_INVALID_PARAMETER ) {
  3173. status = SrvIoCreateFile(
  3174. WorkContext,
  3175. &fileHandle,
  3176. desiredAccess,
  3177. &objectAttributes,
  3178. &ioStatusBlock,
  3179. NULL, // AllocationSize
  3180. 0, // FileAttributes
  3181. FILE_SHARE_READ | FILE_SHARE_WRITE |
  3182. FILE_SHARE_DELETE, // ShareAccess
  3183. FILE_OPEN, // Disposition
  3184. 0, // CreateOptions
  3185. NULL, // EaBuffer
  3186. 0, // EaLength
  3187. CreateFileTypeNone,
  3188. NULL, // ExtraCreateParameters
  3189. IO_FORCE_ACCESS_CHECK, // Options
  3190. transaction->TreeConnect->Share
  3191. );
  3192. }
  3193. ASSERT( status != STATUS_OPLOCK_BREAK_IN_PROGRESS );
  3194. if ( NT_SUCCESS(status) ) {
  3195. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 22, 0 );
  3196. }
  3197. if ( !isUnicode ) {
  3198. RtlFreeUnicodeString( &objectName );
  3199. }
  3200. if ( !NT_SUCCESS( status ) ) {
  3201. //
  3202. // If the user didn't have this permission, update the
  3203. // statistics database.
  3204. //
  3205. if ( status == STATUS_ACCESS_DENIED ) {
  3206. SrvStatistics.AccessPermissionErrors++;
  3207. }
  3208. IF_DEBUG(ERRORS) {
  3209. KdPrint(( "SrvSmbSetPathInformation: SrvIoCreateFile failed: "
  3210. "%X\n", status ));
  3211. }
  3212. SrvSetSmbError( WorkContext, status );
  3213. SmbStatus = SmbTransStatusErrorWithoutData;
  3214. goto Cleanup;
  3215. }
  3216. IF_SMB_DEBUG(QUERY_SET2) {
  3217. KdPrint(( "SrvIoCreateFile succeeded, handle = 0x%p\n", fileHandle ));
  3218. }
  3219. if( informationLevel < SMB_INFO_PASSTHROUGH ) {
  3220. //
  3221. // Verify the information level and the number of input and output
  3222. // data bytes available.
  3223. //
  3224. BOOLEAN error = FALSE;
  3225. switch ( informationLevel ) {
  3226. case SMB_INFO_STANDARD:
  3227. if ( transaction->DataCount < 22 ) {
  3228. IF_DEBUG(SMB_ERRORS) {
  3229. KdPrint(( "SrvSmbSetPathInformation: invalid DataCount %ld\n",
  3230. transaction->DataCount ));
  3231. }
  3232. error = TRUE;
  3233. }
  3234. break;
  3235. case SMB_INFO_QUERY_EA_SIZE:
  3236. case SMB_INFO_QUERY_ALL_EAS:
  3237. if ( transaction->DataCount < 4 ) {
  3238. IF_DEBUG(SMB_ERRORS) {
  3239. KdPrint(( "SrvSmbSetPathInformation: invalid DataCount %ld\n",
  3240. transaction->MaxParameterCount ));
  3241. }
  3242. error = TRUE;
  3243. }
  3244. break;
  3245. default:
  3246. IF_DEBUG(SMB_ERRORS) {
  3247. KdPrint(( "SrvSmbSetPathInformation: invalid info level %ld\n",
  3248. informationLevel ));
  3249. }
  3250. error = TRUE;
  3251. }
  3252. if ( error ) {
  3253. //
  3254. // Just return an error condition.
  3255. //
  3256. SrvSetSmbError2( WorkContext, STATUS_OS2_INVALID_LEVEL, TRUE );
  3257. status = STATUS_OS2_INVALID_LEVEL;
  3258. SmbStatus = SmbTransStatusErrorWithoutData;
  3259. goto Cleanup;
  3260. }
  3261. }
  3262. //
  3263. // Set the appropriate information about the file.
  3264. //
  3265. status = SetPathOrFileInformation(
  3266. WorkContext,
  3267. transaction,
  3268. informationLevel,
  3269. fileHandle,
  3270. (PRESP_SET_PATH_INFORMATION)transaction->OutParameters
  3271. );
  3272. //
  3273. // Close the file--it was only opened to write the attributes.
  3274. //
  3275. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 35, 0 );
  3276. SrvNtClose( fileHandle, TRUE );
  3277. //
  3278. // If an error occurred, return an appropriate response.
  3279. //
  3280. if ( !NT_SUCCESS(status) ) {
  3281. //
  3282. // SetPathOrFileInformation already set the response parameters,
  3283. // so just return an error condition.
  3284. //
  3285. SrvSetSmbError2( WorkContext, status, TRUE );
  3286. SmbStatus = SmbTransStatusErrorWithData;
  3287. goto Cleanup;
  3288. }
  3289. SmbStatus = SmbTransStatusSuccess;
  3290. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSetPathInformation complete.\n" ));
  3291. Cleanup:
  3292. SrvWmiEndContext(WorkContext);
  3293. return SmbStatus;
  3294. } // SrvSmbSetPathInformation