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.

1164 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbdir.c
  5. Abstract:
  6. This module implements directory control SMB processors:
  7. Create Directory
  8. Create Directory2
  9. Delete Directory
  10. Check Directory
  11. --*/
  12. #include "precomp.h"
  13. #include "smbdir.tmh"
  14. #pragma hdrstop
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvSmbCreateDirectory )
  17. #pragma alloc_text( PAGE, SrvSmbCreateDirectory2 )
  18. #pragma alloc_text( PAGE, SrvSmbDeleteDirectory )
  19. #pragma alloc_text( PAGE, SrvSmbCheckDirectory )
  20. #endif
  21. SMB_PROCESSOR_RETURN_TYPE
  22. SrvSmbCreateDirectory (
  23. SMB_PROCESSOR_PARAMETERS
  24. )
  25. /*++
  26. Routine Description:
  27. This routine processes the Create Directory SMB.
  28. Arguments:
  29. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  30. of the parameters to SMB processor routines.
  31. Return Value:
  32. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  33. --*/
  34. {
  35. PREQ_CREATE_DIRECTORY request;
  36. PRESP_CREATE_DIRECTORY response;
  37. NTSTATUS status = STATUS_SUCCESS;
  38. OBJECT_ATTRIBUTES objectAttributes;
  39. IO_STATUS_BLOCK ioStatusBlock;
  40. UNICODE_STRING directoryName;
  41. HANDLE directoryHandle;
  42. PTREE_CONNECT treeConnect;
  43. PSESSION session;
  44. PSHARE share;
  45. BOOLEAN isUnicode;
  46. PAGED_CODE( );
  47. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  48. WorkContext->PreviousSMB = EVENT_TYPE_SMB_CREATE_DIRECTORY;
  49. SrvWmiStartContext(WorkContext);
  50. IF_SMB_DEBUG(DIRECTORY1) {
  51. SrvPrint2( "Create directory request header at 0x%p, response header at 0x%p\n",
  52. WorkContext->RequestHeader,
  53. WorkContext->ResponseHeader );
  54. SrvPrint2( "Create directory request params at 0x%p, response params%p\n",
  55. WorkContext->RequestParameters,
  56. WorkContext->ResponseParameters );
  57. }
  58. request = (PREQ_CREATE_DIRECTORY)WorkContext->RequestParameters;
  59. response = (PRESP_CREATE_DIRECTORY)WorkContext->ResponseParameters;
  60. //
  61. // If a session block has not already been assigned to the current
  62. // work context , verify the UID. If verified, the address of the
  63. // session block corresponding to this user is stored in the
  64. // WorkContext block and the session block is referenced.
  65. //
  66. // Find tree connect corresponding to given TID if a tree connect
  67. // pointer has not already been put in the WorkContext block by an
  68. // AndX command.
  69. //
  70. status = SrvVerifyUidAndTid(
  71. WorkContext,
  72. &session,
  73. &treeConnect,
  74. ShareTypeDisk
  75. );
  76. if ( !NT_SUCCESS(status) ) {
  77. IF_DEBUG(SMB_ERRORS) {
  78. SrvPrint0( "SrvSmbCreateDirectory: Invalid UID or TID\n" );
  79. }
  80. SrvSetSmbError( WorkContext, status );
  81. goto Cleanup;
  82. }
  83. if( session->IsSessionExpired )
  84. {
  85. status = SESSION_EXPIRED_STATUS_CODE;
  86. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  87. goto Cleanup;
  88. }
  89. //
  90. // Get the share block from the tree connect block. This doesn't need
  91. // to be a referenced pointer because the tree connect has it referenced,
  92. // and we just referenced the tree connect.
  93. //
  94. share = treeConnect->Share;
  95. //
  96. // Initialize the string containing the path name. The +1 is to account
  97. // for the ASCII token in the Buffer field of the request SMB.
  98. //
  99. isUnicode = SMB_IS_UNICODE( WorkContext );
  100. status = SrvCanonicalizePathName(
  101. WorkContext,
  102. share,
  103. NULL,
  104. (PVOID)(request->Buffer + 1),
  105. END_OF_REQUEST_SMB( WorkContext ),
  106. TRUE,
  107. isUnicode,
  108. &directoryName
  109. );
  110. if( !NT_SUCCESS( status ) ) {
  111. IF_DEBUG(SMB_ERRORS) {
  112. SrvPrint1( "SrvSmbCreateDirectory: illegal path name: %s\n",
  113. (PSZ)request->Buffer + 1 );
  114. }
  115. SrvSetSmbError( WorkContext, status );
  116. goto Cleanup;
  117. }
  118. //
  119. // Initialize the object attributes structure. Open relative to the
  120. // share root directory handle.
  121. //
  122. SrvInitializeObjectAttributes_U(
  123. &objectAttributes,
  124. &directoryName,
  125. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  126. WorkContext->Session->UsingUppercasePaths) ?
  127. OBJ_CASE_INSENSITIVE : 0L,
  128. NULL,
  129. NULL
  130. );
  131. //
  132. // Attempt to create the directory. Since we must specify some desired
  133. // access, request TRAVERSE_DIRECTORY even though we are going to close
  134. // the directory just after we create it. The SMB protocol has no way
  135. // of specifying attributes, so assume a normal file.
  136. //
  137. IF_SMB_DEBUG(DIRECTORY2) {
  138. SrvPrint1( "Creating directory %wZ\n", objectAttributes.ObjectName );
  139. }
  140. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  141. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  142. status = SrvIoCreateFile(
  143. WorkContext,
  144. &directoryHandle,
  145. FILE_TRAVERSE, // DesiredAccess
  146. &objectAttributes,
  147. &ioStatusBlock,
  148. 0L, // AllocationSize
  149. FILE_ATTRIBUTE_NORMAL, // FileAttributes
  150. 0L, // ShareAccess
  151. FILE_CREATE, // Disposition
  152. FILE_DIRECTORY_FILE, // CreateOptions
  153. NULL, // EaBuffer
  154. 0L, // EaLength
  155. CreateFileTypeNone,
  156. NULL, // ExtraCreateParameters
  157. IO_FORCE_ACCESS_CHECK, // Options
  158. share
  159. );
  160. if ( !isUnicode ) {
  161. RtlFreeUnicodeString( &directoryName );
  162. }
  163. //
  164. // If the user didn't have this permission, update the
  165. // statistics database.
  166. //
  167. if ( status == STATUS_ACCESS_DENIED ) {
  168. SrvStatistics.AccessPermissionErrors++;
  169. }
  170. //
  171. // Special error mapping to return correct error.
  172. //
  173. if ( status == STATUS_OBJECT_NAME_COLLISION &&
  174. !CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection)) {
  175. status = STATUS_ACCESS_DENIED;
  176. }
  177. if ( !NT_SUCCESS(status) ) {
  178. IF_DEBUG(ERRORS) {
  179. SrvPrint1( "SrvCreateDirectory: SrvIoCreateFile failed, "
  180. "status = %X\n", status );
  181. }
  182. SrvSetSmbError( WorkContext, status );
  183. goto Cleanup;
  184. }
  185. SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 23, 0 );
  186. SrvStatistics.TotalFilesOpened++;
  187. IF_SMB_DEBUG(DIRECTORY2) {
  188. SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
  189. directoryHandle );
  190. }
  191. //
  192. // The SMB protocol has no concept of open directories; just close the
  193. // handle now that we have created the directory.
  194. //
  195. SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 36, 0 );
  196. SrvNtClose( directoryHandle, TRUE );
  197. //
  198. // Build the response SMB.
  199. //
  200. response->WordCount = 0;
  201. SmbPutUshort( &response->ByteCount, 0 );
  202. WorkContext->ResponseParameters = NEXT_LOCATION(
  203. response,
  204. RESP_CREATE_DIRECTORY,
  205. 0
  206. );
  207. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbCreateDirectory complete.\n" );
  208. Cleanup:
  209. SrvWmiEndContext(WorkContext);
  210. return SmbStatusSendResponse;
  211. } // SrvSmbCreateDirectory
  212. SMB_TRANS_STATUS
  213. SrvSmbCreateDirectory2 (
  214. IN OUT PWORK_CONTEXT WorkContext
  215. )
  216. /*++
  217. Routine Description:
  218. Processes the Create Directory2 request. This request arrives
  219. in a Transaction2 SMB.
  220. Arguments:
  221. WorkContext - Supplies the address of a Work Context Block
  222. describing the current request. See smbtypes.h for a more
  223. complete description of the valid fields.
  224. Return Value:
  225. BOOLEAN - Indicates whether an error occurred. See smbtypes.h for a
  226. more complete description.
  227. --*/
  228. {
  229. PREQ_CREATE_DIRECTORY2 request;
  230. PRESP_CREATE_DIRECTORY2 response;
  231. NTSTATUS status = STATUS_SUCCESS;
  232. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  233. IO_STATUS_BLOCK ioStatusBlock;
  234. PTRANSACTION transaction;
  235. UNICODE_STRING directoryName;
  236. OBJECT_ATTRIBUTES objectAttributes;
  237. HANDLE directoryHandle;
  238. PFILE_FULL_EA_INFORMATION ntFullEa = NULL;
  239. ULONG ntFullEaLength = 0;
  240. USHORT eaErrorOffset = 0;
  241. PTREE_CONNECT treeConnect;
  242. PSHARE share;
  243. BOOLEAN isUnicode;
  244. PAGED_CODE( );
  245. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  246. WorkContext->PreviousSMB = EVENT_TYPE_SMB_CREATE_DIRECTORY2;
  247. SrvWmiStartContext(WorkContext);
  248. transaction = WorkContext->Parameters.Transaction;
  249. IF_SMB_DEBUG(DIRECTORY1) {
  250. SrvPrint1( "Create Directory2 entered; transaction 0x%p\n",
  251. transaction );
  252. }
  253. request = (PREQ_CREATE_DIRECTORY2)transaction->InParameters;
  254. response = (PRESP_CREATE_DIRECTORY2)transaction->OutParameters;
  255. //
  256. // Verify that enough parameter bytes were sent and that we're allowed
  257. // to return enough parameter bytes.
  258. //
  259. if ( (transaction->ParameterCount <
  260. sizeof(REQ_CREATE_DIRECTORY2)) ||
  261. (transaction->MaxParameterCount <
  262. sizeof(RESP_CREATE_DIRECTORY2)) ) {
  263. //
  264. // Not enough parameter bytes were sent.
  265. //
  266. IF_DEBUG(SMB_ERRORS) {
  267. SrvPrint2( "SrvSmbCreateDirectory2: bad parameter byte counts: "
  268. "%ld %ld\n",
  269. transaction->ParameterCount,
  270. transaction->MaxParameterCount );
  271. }
  272. SrvLogInvalidSmb( WorkContext );
  273. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  274. status = STATUS_INVALID_SMB;
  275. SmbStatus = SmbTransStatusErrorWithoutData;
  276. goto Cleanup;
  277. }
  278. //
  279. // Get the tree connect block from the transaction block and the share
  280. // block from the tree connect block. These don't need to be referenced
  281. // pointers because they are referenced by the transaction and the
  282. // tree connect, respectively.
  283. //
  284. treeConnect = transaction->TreeConnect;
  285. share = treeConnect->Share;
  286. //
  287. // Initialize the string containing the path name.
  288. //
  289. isUnicode = SMB_IS_UNICODE( WorkContext );
  290. status = SrvCanonicalizePathName(
  291. WorkContext,
  292. share,
  293. NULL,
  294. request->Buffer,
  295. END_OF_TRANSACTION_PARAMETERS( transaction ),
  296. TRUE,
  297. isUnicode,
  298. &directoryName
  299. );
  300. if( !NT_SUCCESS( status ) ) {
  301. IF_DEBUG(SMB_ERRORS) {
  302. SrvPrint1( "SrvSmbCreateDirectory2: illegal path name: %ws\n",
  303. directoryName.Buffer );
  304. }
  305. SrvSetSmbError( WorkContext, status );
  306. SmbStatus = SmbTransStatusErrorWithoutData;
  307. goto Cleanup;
  308. }
  309. //
  310. // Initialize the object attributes structure. Open relative to the
  311. // share root directory handle.
  312. //
  313. SrvInitializeObjectAttributes_U(
  314. &objectAttributes,
  315. &directoryName,
  316. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  317. WorkContext->Session->UsingUppercasePaths) ?
  318. OBJ_CASE_INSENSITIVE : 0L,
  319. NULL,
  320. NULL
  321. );
  322. //
  323. // If an FEALIST was passed and it has valid size, convert it to
  324. // NT style. SrvOs2FeaListToNt allocates space for the NT full EA
  325. // list which must be deallocated. Note that sizeof(FEALIST) includes
  326. // space for 1 FEA entry. Without at least much information, the EA
  327. // code below should be skipped.
  328. //
  329. if ( transaction->DataCount > sizeof(FEALIST) &&
  330. SmbGetUlong( &((PFEALIST)transaction->InData)->cbList ) > sizeof(FEALIST) &&
  331. SmbGetUlong( &((PFEALIST)transaction->InData)->cbList ) <= transaction->DataCount ) {
  332. status = SrvOs2FeaListToNt(
  333. (PFEALIST)transaction->InData,
  334. &ntFullEa,
  335. &ntFullEaLength,
  336. &eaErrorOffset
  337. );
  338. if ( !NT_SUCCESS(status) ) {
  339. IF_DEBUG(ERRORS) {
  340. SrvPrint1( "SrvSmbCreateDirectory2: SrvOs2FeaListToNt failed, "
  341. "status = %X\n", status );
  342. }
  343. if ( !isUnicode ) {
  344. RtlFreeUnicodeString( &directoryName );
  345. }
  346. SrvSetSmbError2( WorkContext, status, TRUE );
  347. transaction->SetupCount = 0;
  348. transaction->ParameterCount = 2;
  349. SmbPutUshort( &response->EaErrorOffset, eaErrorOffset );
  350. transaction->DataCount = 0;
  351. SmbStatus = SmbTransStatusErrorWithData;
  352. goto Cleanup;
  353. }
  354. }
  355. //
  356. // Attempt to create the directory. Since we must specify some desired
  357. // access, request FILE_TRAVERSE even though we are going to close
  358. // the directory just after we create it. The SMB protocol has no way
  359. // of specifying attributes, so assume a normal file.
  360. //
  361. IF_SMB_DEBUG(DIRECTORY2) {
  362. SrvPrint1( "Creating directory %wZ\n", objectAttributes.ObjectName );
  363. }
  364. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  365. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  366. //
  367. // Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
  368. // component, the Io subsystem does not check it for us.
  369. //
  370. if( ARGUMENT_PRESENT( ntFullEa ) ) {
  371. ULONG ntEaErrorOffset = 0;
  372. status = IoCheckEaBufferValidity( ntFullEa, ntFullEaLength, &ntEaErrorOffset );
  373. eaErrorOffset = (USHORT)ntEaErrorOffset;
  374. } else {
  375. status = STATUS_SUCCESS;
  376. }
  377. if( NT_SUCCESS( status ) ) {
  378. status = SrvIoCreateFile(
  379. WorkContext,
  380. &directoryHandle,
  381. FILE_TRAVERSE, // DesiredAccess
  382. &objectAttributes,
  383. &ioStatusBlock,
  384. 0L, // AllocationSize
  385. FILE_ATTRIBUTE_NORMAL, // FileAttributes
  386. 0L, // ShareAccess
  387. FILE_CREATE, // Disposition
  388. FILE_DIRECTORY_FILE, // CreateOptions
  389. ntFullEa, // EaBuffer
  390. ntFullEaLength, // EaLength
  391. CreateFileTypeNone,
  392. NULL, // ExtraCreateParameters
  393. IO_FORCE_ACCESS_CHECK, // Options
  394. share
  395. );
  396. }
  397. if ( !isUnicode ) {
  398. RtlFreeUnicodeString( &directoryName );
  399. }
  400. //
  401. // If the user didn't have this permission, update the statistics
  402. // database.
  403. //
  404. if ( status == STATUS_ACCESS_DENIED ) {
  405. SrvStatistics.AccessPermissionErrors++;
  406. }
  407. if ( ARGUMENT_PRESENT( ntFullEa ) ) {
  408. DEALLOCATE_NONPAGED_POOL( ntFullEa );
  409. }
  410. if ( !NT_SUCCESS(status) ) {
  411. IF_DEBUG(ERRORS) {
  412. SrvPrint1( "SrvCreateDirectory2: SrvIoCreateFile failed, "
  413. "status = %X\n", status );
  414. }
  415. SrvSetSmbError2( WorkContext, status, TRUE );
  416. transaction->SetupCount = 0;
  417. transaction->ParameterCount = 2;
  418. SmbPutUshort( &response->EaErrorOffset, eaErrorOffset );
  419. transaction->DataCount = 0;
  420. SmbStatus = SmbTransStatusErrorWithData;
  421. goto Cleanup;
  422. }
  423. IF_SMB_DEBUG(DIRECTORY2) {
  424. SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
  425. directoryHandle );
  426. }
  427. //
  428. // The SMB protocol has no concept of open directories; just close the
  429. // handle now that we have created the directory.
  430. //
  431. SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 24, 0 );
  432. SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 37, 0 );
  433. SrvNtClose( directoryHandle, TRUE );
  434. //
  435. // Build the output parameter and data structures.
  436. //
  437. transaction->SetupCount = 0;
  438. transaction->ParameterCount = 2;
  439. SmbPutUshort( &response->EaErrorOffset, 0 );
  440. transaction->DataCount = 0;
  441. SmbStatus = SmbTransStatusSuccess;
  442. Cleanup:
  443. SrvWmiEndContext(WorkContext);
  444. return SmbStatus;
  445. } // SrvSmbCreateDirectory2
  446. SMB_PROCESSOR_RETURN_TYPE
  447. SrvSmbDeleteDirectory (
  448. SMB_PROCESSOR_PARAMETERS
  449. )
  450. /*++
  451. Routine Description:
  452. This routine processes the Delete Directory SMB.
  453. Arguments:
  454. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  455. of the parameters to SMB processor routines.
  456. Return Value:
  457. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  458. --*/
  459. {
  460. PREQ_DELETE_DIRECTORY request;
  461. PRESP_DELETE_DIRECTORY response;
  462. NTSTATUS status = STATUS_SUCCESS;
  463. OBJECT_ATTRIBUTES objectAttributes;
  464. IO_STATUS_BLOCK ioStatusBlock;
  465. UNICODE_STRING directoryName;
  466. HANDLE directoryHandle;
  467. FILE_DISPOSITION_INFORMATION fileDispositionInformation;
  468. PTREE_CONNECT treeConnect;
  469. PSESSION session;
  470. PSHARE share;
  471. BOOLEAN isUnicode;
  472. PAGED_CODE( );
  473. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  474. WorkContext->PreviousSMB = EVENT_TYPE_SMB_DELETE_DIRECTORY;
  475. SrvWmiStartContext(WorkContext);
  476. IF_SMB_DEBUG(DIRECTORY1) {
  477. SrvPrint2( "Delete directory request header at 0x%p, response header at 0x%p\n",
  478. WorkContext->RequestHeader,
  479. WorkContext->ResponseHeader );
  480. SrvPrint2( "Delete directory request params at 0x%p, response params at 0x%p\n",
  481. WorkContext->RequestParameters,
  482. WorkContext->ResponseParameters );
  483. }
  484. request = (PREQ_DELETE_DIRECTORY)WorkContext->RequestParameters;
  485. response = (PRESP_DELETE_DIRECTORY)WorkContext->ResponseParameters;
  486. //
  487. // If a session block has not already been assigned to the current
  488. // work context , verify the UID. If verified, the address of the
  489. // session block corresponding to this user is stored in the WorkContext
  490. // block and the session block is referenced.
  491. //
  492. // Find tree connect corresponding to given TID if a tree connect
  493. // pointer has not already been put in the WorkContext block by an
  494. // AndX command.
  495. //
  496. status = SrvVerifyUidAndTid(
  497. WorkContext,
  498. &session,
  499. &treeConnect,
  500. ShareTypeDisk
  501. );
  502. if ( !NT_SUCCESS(status) ) {
  503. IF_DEBUG(SMB_ERRORS) {
  504. SrvPrint0( "SrvSmbDeleteDirectory: Invalid UID or TID\n" );
  505. }
  506. SrvSetSmbError( WorkContext, status );
  507. goto Cleanup;
  508. }
  509. if( session->IsSessionExpired )
  510. {
  511. status = SESSION_EXPIRED_STATUS_CODE;
  512. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  513. goto Cleanup;
  514. }
  515. //
  516. // Get the share block from the tree connect block. This doesn't need
  517. // to be a referenced pointer becsue the tree connect has it referenced,
  518. // and we just referenced the tree connect.
  519. //
  520. share = treeConnect->Share;
  521. //
  522. // Initialize the string containing the path name. The +1 is to account
  523. // for the ASCII token in the Buffer field of the request SMB.
  524. //
  525. isUnicode = SMB_IS_UNICODE( WorkContext );
  526. status = SrvCanonicalizePathName(
  527. WorkContext,
  528. share,
  529. NULL,
  530. (PVOID)(request->Buffer + 1),
  531. END_OF_REQUEST_SMB( WorkContext ),
  532. TRUE,
  533. isUnicode,
  534. &directoryName
  535. );
  536. if( !NT_SUCCESS( status ) ) {
  537. IF_DEBUG(SMB_ERRORS) {
  538. SrvPrint1( "SrvSmbDeleteDirectory: illegal path name: %s\n",
  539. (PSZ)request->Buffer + 1 );
  540. }
  541. SrvSetSmbError( WorkContext, status );
  542. goto Cleanup;
  543. }
  544. //
  545. // If the client is trying to delete the root of the share, reject
  546. // the request.
  547. //
  548. if ( directoryName.Length < sizeof(WCHAR) ) {
  549. IF_DEBUG(SMB_ERRORS) {
  550. SrvPrint0( "SrvSmbDeleteDirectory: attempting to delete share root\n" );
  551. }
  552. if ( !isUnicode ) {
  553. RtlFreeUnicodeString( &directoryName );
  554. }
  555. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  556. goto Cleanup;
  557. }
  558. //
  559. // Initialize the object attributes structure. Open relative to the
  560. // share root directory handle.
  561. //
  562. SrvInitializeObjectAttributes_U(
  563. &objectAttributes,
  564. &directoryName,
  565. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  566. WorkContext->Session->UsingUppercasePaths) ?
  567. OBJ_CASE_INSENSITIVE : 0L,
  568. NULL,
  569. NULL
  570. );
  571. //
  572. // Attempt to open the directory. We just need DELETE access to delete
  573. // the directory.
  574. //
  575. IF_SMB_DEBUG(DIRECTORY2) {
  576. SrvPrint1( "Opening directory %wZ\n", &directoryName );
  577. }
  578. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  579. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  580. status = SrvIoCreateFile(
  581. WorkContext,
  582. &directoryHandle,
  583. DELETE, // DesiredAccess
  584. &objectAttributes,
  585. &ioStatusBlock,
  586. NULL, // AllocationSize
  587. 0L, // FileAttributes
  588. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  589. FILE_OPEN, // Disposition
  590. FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, // CreateOptions
  591. NULL, // EaBuffer
  592. 0L, // EaLength
  593. CreateFileTypeNone,
  594. NULL, // ExtraCreateParameters
  595. IO_FORCE_ACCESS_CHECK, // Options
  596. share
  597. );
  598. if( status == STATUS_INVALID_PARAMETER ) {
  599. status = SrvIoCreateFile(
  600. WorkContext,
  601. &directoryHandle,
  602. DELETE, // DesiredAccess
  603. &objectAttributes,
  604. &ioStatusBlock,
  605. NULL, // AllocationSize
  606. 0L, // FileAttributes
  607. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  608. FILE_OPEN, // Disposition
  609. FILE_DIRECTORY_FILE, // CreateOptions
  610. NULL, // EaBuffer
  611. 0L, // EaLength
  612. CreateFileTypeNone,
  613. NULL, // ExtraCreateParameters
  614. IO_FORCE_ACCESS_CHECK, // Options
  615. share
  616. );
  617. }
  618. //
  619. // If the user didn't have this permission, update the
  620. // statistics database.
  621. //
  622. if ( status == STATUS_ACCESS_DENIED ) {
  623. SrvStatistics.AccessPermissionErrors++;
  624. }
  625. if ( !NT_SUCCESS(status) ) {
  626. IF_DEBUG(ERRORS) {
  627. SrvPrint2( "SrvDeleteDirectory: SrvIoCreateFile (%s) failed, "
  628. "status = %X\n", (PSZ)request->Buffer + 1, status );
  629. }
  630. //
  631. // If returned error is STATUS_NOT_A_DIRECTORY, downlevel clients
  632. // expect ERROR_ACCESS_DENIED
  633. //
  634. if ( (status == STATUS_NOT_A_DIRECTORY) &&
  635. !CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
  636. status = STATUS_ACCESS_DENIED;
  637. }
  638. SrvSetSmbError( WorkContext, status );
  639. if ( !isUnicode ) {
  640. RtlFreeUnicodeString( &directoryName );
  641. }
  642. goto Cleanup;
  643. }
  644. SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 25, 0 );
  645. IF_SMB_DEBUG(DIRECTORY2) {
  646. SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
  647. directoryHandle );
  648. }
  649. //
  650. // Delete the directory with NtSetInformationFile.
  651. //
  652. fileDispositionInformation.DeleteFile = TRUE;
  653. status = NtSetInformationFile(
  654. directoryHandle,
  655. &ioStatusBlock,
  656. &fileDispositionInformation,
  657. sizeof(FILE_DISPOSITION_INFORMATION),
  658. FileDispositionInformation
  659. );
  660. if ( !NT_SUCCESS(status) ) {
  661. IF_DEBUG(ERRORS) {
  662. SrvPrint2( "SrvDeleteDirectory: NtSetInformationFile for directory "
  663. "%s returned %X\n", (PSZ)request->Buffer + 1, status );
  664. }
  665. SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 38, 0 );
  666. SrvNtClose( directoryHandle, TRUE );
  667. if ( !isUnicode ) {
  668. RtlFreeUnicodeString( &directoryName );
  669. }
  670. SrvSetSmbError( WorkContext, status );
  671. goto Cleanup;
  672. } else {
  673. //
  674. // Remove this directory name from the cache, since it has been deleted
  675. //
  676. SrvRemoveCachedDirectoryName( WorkContext, &directoryName );
  677. }
  678. IF_SMB_DEBUG(DIRECTORY2) {
  679. SrvPrint0( "SrvSmbDeleteDirectory: NtSetInformationFile succeeded.\n" );
  680. }
  681. //
  682. // Close the directory handle so that the directory will be deleted.
  683. //
  684. SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 39, 0 );
  685. SrvNtClose( directoryHandle, TRUE );
  686. //
  687. // Close all DOS directory searches on this directory and its
  688. // subdirectories.
  689. //
  690. SrvCloseSearches(
  691. treeConnect->Connection,
  692. (PSEARCH_FILTER_ROUTINE)SrvSearchOnDelete,
  693. (PVOID) &directoryName,
  694. (PVOID) treeConnect
  695. );
  696. if ( !isUnicode ) {
  697. RtlFreeUnicodeString( &directoryName );
  698. }
  699. //
  700. // Build the response SMB.
  701. //
  702. response->WordCount = 0;
  703. SmbPutUshort( &response->ByteCount, 0 );
  704. WorkContext->ResponseParameters = NEXT_LOCATION(
  705. response,
  706. RESP_DELETE_DIRECTORY,
  707. 0
  708. );
  709. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbDeleteDirectory complete.\n" );
  710. Cleanup:
  711. SrvWmiEndContext(WorkContext);
  712. return SmbStatusSendResponse;
  713. } // SrvSmbDeleteDirectory
  714. SMB_PROCESSOR_RETURN_TYPE
  715. SrvSmbCheckDirectory (
  716. SMB_PROCESSOR_PARAMETERS
  717. )
  718. /*++
  719. Routine Description:
  720. This routine processes the Check Directory SMB.
  721. Arguments:
  722. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  723. of the parameters to SMB processor routines.
  724. Return Value:
  725. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  726. --*/
  727. {
  728. PREQ_CHECK_DIRECTORY request;
  729. PRESP_CHECK_DIRECTORY response;
  730. NTSTATUS status = STATUS_SUCCESS;
  731. OBJECT_ATTRIBUTES objectAttributes;
  732. IO_STATUS_BLOCK ioStatusBlock;
  733. UNICODE_STRING directoryName;
  734. FILE_NETWORK_OPEN_INFORMATION fileInformation;
  735. PTREE_CONNECT treeConnect;
  736. PSESSION session;
  737. PSHARE share;
  738. BOOLEAN isUnicode;
  739. PAGED_CODE( );
  740. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  741. WorkContext->PreviousSMB = EVENT_TYPE_SMB_CHECK_DIRECTORY;
  742. SrvWmiStartContext(WorkContext);
  743. IF_SMB_DEBUG(DIRECTORY1) {
  744. SrvPrint2( "Check directory request header at 0x%p, response header at 0x%p\n",
  745. WorkContext->RequestHeader,
  746. WorkContext->ResponseHeader );
  747. SrvPrint2( "Check directory request params at 0x%p, response params at 0x%p\n",
  748. WorkContext->RequestParameters,
  749. WorkContext->ResponseParameters );
  750. }
  751. request = (PREQ_CHECK_DIRECTORY)WorkContext->RequestParameters;
  752. response = (PRESP_CHECK_DIRECTORY)WorkContext->ResponseParameters;
  753. //
  754. // If a session block has not already been assigned to the current
  755. // work context , verify the UID. If verified, the address of the
  756. // session block corresponding to this user is stored in the WorkContext
  757. // block and the session block is referenced.
  758. //
  759. // Find tree connect corresponding to given TID if a tree connect
  760. // pointer has not already been put in the WorkContext block by an
  761. // AndX command.
  762. //
  763. status = SrvVerifyUidAndTid(
  764. WorkContext,
  765. &session,
  766. &treeConnect,
  767. ShareTypeDisk
  768. );
  769. if ( !NT_SUCCESS(status) ) {
  770. IF_DEBUG(SMB_ERRORS) {
  771. SrvPrint0( "SrvSmbCheckDirectory: Invalid UID or TID\n" );
  772. }
  773. SrvSetSmbError( WorkContext, status );
  774. goto Cleanup;
  775. }
  776. if( session->IsSessionExpired )
  777. {
  778. status = SESSION_EXPIRED_STATUS_CODE;
  779. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  780. goto Cleanup;
  781. }
  782. //
  783. // Get the share block from the tree connect block. This doesn't need
  784. // to be a referenced pointer because the tree connect has it referenced,
  785. // and we just referenced the tree connect.
  786. //
  787. share = treeConnect->Share;
  788. //
  789. // Initialize the string containing the path name. The +1 is to account
  790. // for the ASCII token in the Buffer field of the request SMB.
  791. //
  792. isUnicode = SMB_IS_UNICODE( WorkContext );
  793. status = SrvCanonicalizePathName(
  794. WorkContext,
  795. share,
  796. NULL,
  797. (PVOID)(request->Buffer + 1),
  798. END_OF_REQUEST_SMB( WorkContext ),
  799. TRUE,
  800. isUnicode,
  801. &directoryName
  802. );
  803. if( !NT_SUCCESS( status ) ) {
  804. IF_DEBUG(SMB_ERRORS) {
  805. SrvPrint1( "SrvSmbCheckDirectory: illegal path name: %s\n",
  806. (PSZ)request->Buffer + 1 );
  807. }
  808. SrvSetSmbError( WorkContext, status );
  809. goto Cleanup;
  810. }
  811. //
  812. // See if we can find this directory in the CachedDirectoryList
  813. //
  814. if( SrvIsDirectoryCached( WorkContext, &directoryName ) == FALSE ) {
  815. //
  816. // Is not in the cache, must really check.
  817. //
  818. SrvInitializeObjectAttributes_U(
  819. &objectAttributes,
  820. &directoryName,
  821. (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
  822. WorkContext->Session->UsingUppercasePaths) ?
  823. OBJ_CASE_INSENSITIVE : 0L,
  824. NULL,
  825. NULL
  826. );
  827. status = IMPERSONATE( WorkContext );
  828. if( NT_SUCCESS( status ) ) {
  829. status = SrvGetShareRootHandle( share );
  830. if( NT_SUCCESS( status ) ) {
  831. ULONG FileOptions = FILE_DIRECTORY_FILE;
  832. if (SeSinglePrivilegeCheck(
  833. SeExports->SeBackupPrivilege,
  834. KernelMode)) {
  835. FileOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
  836. }
  837. //
  838. // The file name is always relative to the share root
  839. //
  840. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  841. if( !NT_SUCCESS(status) )
  842. {
  843. goto SnapError;
  844. }
  845. //
  846. // Find out what this thing is
  847. //
  848. if( IoFastQueryNetworkAttributes( &objectAttributes,
  849. FILE_TRAVERSE,
  850. FileOptions,
  851. &ioStatusBlock,
  852. &fileInformation
  853. ) == FALSE ) {
  854. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  855. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  856. }
  857. status = ioStatusBlock.Status;
  858. //
  859. // If the media was changed and we can come up with a new share root handle,
  860. // then we should retry the operation
  861. //
  862. if( SrvRetryDueToDismount( share, status ) ) {
  863. status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
  864. if( !NT_SUCCESS(status) )
  865. {
  866. goto SnapError;
  867. }
  868. if( IoFastQueryNetworkAttributes( &objectAttributes,
  869. FILE_TRAVERSE,
  870. FILE_DIRECTORY_FILE,
  871. &ioStatusBlock,
  872. &fileInformation
  873. ) == FALSE ) {
  874. SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
  875. ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  876. }
  877. status = ioStatusBlock.Status;
  878. }
  879. SnapError:
  880. SrvReleaseShareRootHandle( share );
  881. }
  882. REVERT();
  883. }
  884. }
  885. if ( !isUnicode ) {
  886. RtlFreeUnicodeString( &directoryName );
  887. }
  888. if ( NT_SUCCESS(status) ) {
  889. response->WordCount = 0;
  890. SmbPutUshort( &response->ByteCount, 0 );
  891. WorkContext->ResponseParameters = NEXT_LOCATION(
  892. response,
  893. RESP_CHECK_DIRECTORY,
  894. 0
  895. );
  896. } else {
  897. //
  898. // If the user didn't have this permission, update the
  899. // statistics database.
  900. //
  901. if ( status == STATUS_ACCESS_DENIED ) {
  902. SrvStatistics.AccessPermissionErrors++;
  903. }
  904. if (CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection)) {
  905. SrvSetSmbError( WorkContext, status );
  906. } else {
  907. SrvSetSmbError( WorkContext, STATUS_OBJECT_PATH_NOT_FOUND );
  908. }
  909. }
  910. IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbCheckDirectory complete.\n" );
  911. Cleanup:
  912. SrvWmiEndContext(WorkContext);
  913. return SmbStatusSendResponse;
  914. } // SrvSmbCheckDirectory