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.

5198 lines
142 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. open.c
  5. Abstract:
  6. This module contains the routine called by processing routines for
  7. the various flavors of Open SMBs (SrvCreateFile) and its
  8. subroutines.
  9. !!! Need to use SrvEnableFcbOpens to determine whether to fold FCB
  10. opens together.
  11. Author:
  12. David Treadwell (davidtr) 23-Nov-1989
  13. Chuck Lenzmeier (chuckl)
  14. Manny Weiser (mannyw)
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #include "open.tmh"
  19. #pragma hdrstop
  20. #define BugCheckFileId SRV_FILE_OPEN
  21. //
  22. // Local functions
  23. //
  24. NTSTATUS
  25. DoNormalOpen(
  26. OUT PRFCB *Rfcb,
  27. IN PMFCB Mfcb,
  28. IN OUT PWORK_CONTEXT WorkContext,
  29. OUT PIO_STATUS_BLOCK IoStatusBlock,
  30. IN USHORT SmbDesiredAccess,
  31. IN USHORT SmbFileAttributes,
  32. IN USHORT SmbOpenFunction,
  33. IN ULONG SmbAllocationSize,
  34. IN PUNICODE_STRING RelativeName,
  35. IN PVOID EaBuffer OPTIONAL,
  36. IN ULONG EaLength,
  37. OUT PULONG EaErrorOffset OPTIONAL,
  38. OUT PBOOLEAN LfcbAddedToMfcbList,
  39. IN OPLOCK_TYPE RequestedOplockType
  40. );
  41. NTSTATUS
  42. DoCompatibilityOpen(
  43. OUT PRFCB *Rfcb,
  44. IN PMFCB Mfcb,
  45. IN OUT PWORK_CONTEXT WorkContext,
  46. OUT PIO_STATUS_BLOCK IoStatusBlock,
  47. IN USHORT SmbDesiredAccess,
  48. IN USHORT SmbFileAttributes,
  49. IN USHORT SmbOpenFunction,
  50. IN ULONG SmbAllocationSize,
  51. IN PUNICODE_STRING RelativeName,
  52. IN PVOID EaBuffer OPTIONAL,
  53. IN ULONG EaLength,
  54. OUT PULONG EaErrorOffset OPTIONAL,
  55. OUT PBOOLEAN LfcbAddedToMfcbList,
  56. IN OPLOCK_TYPE RequestedOplockType
  57. );
  58. NTSTATUS
  59. DoFcbOpen(
  60. OUT PRFCB *Rfcb,
  61. IN PMFCB Mfcb,
  62. IN OUT PWORK_CONTEXT WorkContext,
  63. OUT PIO_STATUS_BLOCK IoStatusBlock,
  64. IN USHORT SmbFileAttributes,
  65. IN USHORT SmbOpenFunction,
  66. IN ULONG SmbAllocationSize,
  67. IN PUNICODE_STRING RelativeName,
  68. IN PVOID EaBuffer OPTIONAL,
  69. IN ULONG EaLength,
  70. OUT PULONG EaErrorOffset OPTIONAL,
  71. OUT PBOOLEAN LfcbAddedToMfcbList
  72. );
  73. NTSTATUS
  74. DoCommDeviceOpen (
  75. IN OUT PWORK_CONTEXT WorkContext,
  76. OUT PIO_STATUS_BLOCK IoStatusBlock,
  77. IN USHORT SmbDesiredAccess,
  78. IN USHORT SmbOpenFunction,
  79. OUT PRFCB *Rfcb,
  80. IN PMFCB Mfcb,
  81. OUT PBOOLEAN LfcbAddedToMfcbList
  82. );
  83. PTABLE_ENTRY
  84. FindAndClaimFileTableEntry (
  85. IN PCONNECTION Connection,
  86. OUT PSHORT FidIndex
  87. );
  88. NTSTATUS
  89. CompleteOpen(
  90. OUT PRFCB *Rfcb,
  91. IN PMFCB Mfcb,
  92. IN OUT PWORK_CONTEXT WorkContext,
  93. IN PLFCB ExistingLfcb OPTIONAL,
  94. IN HANDLE FileHandle OPTIONAL,
  95. IN PACCESS_MASK RemoteGrantedAccess OPTIONAL,
  96. IN ULONG ShareAccess,
  97. IN ULONG FileMode,
  98. IN BOOLEAN CompatibilityOpen,
  99. IN BOOLEAN FcbOpen,
  100. OUT PBOOLEAN LfcbAddedToMfcbList
  101. );
  102. BOOLEAN SRVFASTCALL
  103. MapCompatibilityOpen(
  104. IN PUNICODE_STRING FileName,
  105. IN OUT PUSHORT SmbDesiredAccess
  106. );
  107. NTSTATUS SRVFASTCALL
  108. MapDesiredAccess(
  109. IN USHORT SmbDesiredAccess,
  110. OUT PACCESS_MASK NtDesiredAccess
  111. );
  112. NTSTATUS SRVFASTCALL
  113. MapOpenFunction(
  114. IN USHORT SmbOpenFunction,
  115. OUT PULONG CreateDisposition
  116. );
  117. NTSTATUS SRVFASTCALL
  118. MapShareAccess(
  119. IN USHORT SmbDesiredAccess,
  120. OUT PULONG NtShareAccess
  121. );
  122. NTSTATUS SRVFASTCALL
  123. MapCacheHints(
  124. IN USHORT SmbDesiredAccess,
  125. IN OUT PULONG NtCreateFlags
  126. );
  127. BOOLEAN
  128. SetDefaultPipeMode (
  129. IN HANDLE FileHandle
  130. );
  131. NTSTATUS
  132. RemapPipeName(
  133. IN PANSI_STRING AnsiServerName OPTIONAL,
  134. IN PUNICODE_STRING ServerName OPTIONAL,
  135. IN OUT PUNICODE_STRING NewRelativeName,
  136. OUT PBOOLEAN Remapped
  137. );
  138. BOOLEAN
  139. SrvFailMdlReadDev (
  140. IN PFILE_OBJECT FileObject,
  141. IN PLARGE_INTEGER FileOffset,
  142. IN ULONG Length,
  143. IN ULONG LockKey,
  144. OUT PMDL *MdlChain,
  145. OUT PIO_STATUS_BLOCK IoStatus,
  146. IN PDEVICE_OBJECT DeviceObject
  147. );
  148. BOOLEAN
  149. SrvFailPrepareMdlWriteDev(
  150. IN PFILE_OBJECT FileObject,
  151. IN PLARGE_INTEGER FileOffset,
  152. IN ULONG Length,
  153. IN ULONG LockKey,
  154. OUT PMDL *MdlChain,
  155. OUT PIO_STATUS_BLOCK IoStatus,
  156. IN PDEVICE_OBJECT DeviceObject
  157. );
  158. #ifdef ALLOC_PRAGMA
  159. #pragma alloc_text( PAGE, RemapPipeName )
  160. #pragma alloc_text( PAGE, SrvCreateFile )
  161. #pragma alloc_text( PAGE, DoNormalOpen )
  162. #pragma alloc_text( PAGE, DoCompatibilityOpen )
  163. #pragma alloc_text( PAGE, DoFcbOpen )
  164. #pragma alloc_text( PAGE, CompleteOpen )
  165. #pragma alloc_text( PAGE, MapCompatibilityOpen )
  166. #pragma alloc_text( PAGE, MapDesiredAccess )
  167. #pragma alloc_text( PAGE, MapOpenFunction )
  168. #pragma alloc_text( PAGE, MapCacheHints )
  169. #pragma alloc_text( PAGE, MapShareAccess )
  170. #pragma alloc_text( PAGE, SrvNtCreateFile )
  171. #pragma alloc_text( PAGE, SetDefaultPipeMode )
  172. #pragma alloc_text( PAGE8FIL, FindAndClaimFileTableEntry )
  173. #pragma alloc_text( PAGE, SrvFailMdlReadDev )
  174. #pragma alloc_text( PAGE, SrvFailPrepareMdlWriteDev )
  175. #endif
  176. NTSTATUS
  177. RemapPipeName(
  178. IN PANSI_STRING AnsiServerName,
  179. IN PUNICODE_STRING UnicodeName,
  180. IN OUT PUNICODE_STRING NewRelativeName,
  181. OUT PBOOLEAN Remapped
  182. )
  183. /*++
  184. Routine Description:
  185. Remaps a pipe name by prepending "$$\<AnsiServerName>\" to the
  186. relative pipe name (without the trailing spaces in AnsiServerName).
  187. Arguments:
  188. AnsiServerName - NetBIOS server name, or
  189. UnicodeName - UNICODE server name
  190. NewRelativeName - pointer to pipe name; on successful return,
  191. points to newly allocated memory for remapped pipe name.
  192. This memory must be freed by the caller.
  193. Remapped - set to TRUE if the name was remapped
  194. Return Value:
  195. NTSTATUS - Indicates what occurred.
  196. --*/
  197. {
  198. UNICODE_STRING OldRelativeName;
  199. UNICODE_STRING UnicodeServerName;
  200. ULONG nameLength;
  201. PWCH nextLocation;
  202. NTSTATUS status;
  203. int i;
  204. PAGED_CODE();
  205. *Remapped = FALSE;
  206. //
  207. // Do not remap the pipe name if it is in our SrvNoRemapPipeNames list
  208. //
  209. ACQUIRE_LOCK_SHARED( &SrvConfigurationLock );
  210. for ( i = 0; SrvNoRemapPipeNames[i] != NULL ; i++ ) {
  211. UNICODE_STRING NoRemap;
  212. RtlInitUnicodeString( &NoRemap, SrvNoRemapPipeNames[i] );
  213. if( RtlCompareUnicodeString( &NoRemap, NewRelativeName, TRUE ) == 0 ) {
  214. //
  215. // This is a pipe name that we are not supposed to remap. We
  216. // return STATUS_SUCCESS, but indicate to our caller that we did
  217. // not remap the pipe name
  218. //
  219. RELEASE_LOCK( &SrvConfigurationLock );
  220. return STATUS_SUCCESS;
  221. }
  222. }
  223. RELEASE_LOCK( &SrvConfigurationLock );
  224. //
  225. // Save RelativeName before changing it to point to new memory.
  226. //
  227. OldRelativeName = *NewRelativeName;
  228. //
  229. // Trim the trailing spaces from the server name.
  230. // We know that the last character is a space,
  231. // because server name is a netbios name.
  232. //
  233. if( !ARGUMENT_PRESENT( UnicodeName ) ) {
  234. USHORT SavedLength;
  235. ASSERT(AnsiServerName->Length == 16);
  236. ASSERT(AnsiServerName->Buffer[AnsiServerName->Length - 1] == ' ');
  237. SavedLength = AnsiServerName->Length;
  238. while (AnsiServerName->Length > 0 &&
  239. AnsiServerName->Buffer[AnsiServerName->Length - 1] == ' ') {
  240. AnsiServerName->Length--;
  241. }
  242. //
  243. // Convert the server name from ANSI to Unicode.
  244. //
  245. status = RtlAnsiStringToUnicodeString(
  246. &UnicodeServerName,
  247. AnsiServerName,
  248. TRUE);
  249. AnsiServerName->Length = SavedLength;
  250. if (! NT_SUCCESS(status)) {
  251. return status;
  252. }
  253. } else {
  254. UnicodeServerName = *UnicodeName;
  255. }
  256. //
  257. // Allocate space for new relative name ("$$\server\oldrelative").
  258. // Start by calculating the string length, and then add one more WCHAR
  259. // for zero-termination.
  260. //
  261. nameLength = (sizeof(L'$') +
  262. sizeof(L'$') +
  263. sizeof(L'\\') +
  264. UnicodeServerName.Length +
  265. sizeof(L'\\') +
  266. OldRelativeName.Length);
  267. NewRelativeName->Length = (USHORT)nameLength;
  268. if( NewRelativeName->Length != nameLength ) {
  269. //
  270. // Oh no -- string length overflow!
  271. //
  272. if( !ARGUMENT_PRESENT( UnicodeName ) ) {
  273. RtlFreeUnicodeString(&UnicodeServerName);
  274. }
  275. return STATUS_INVALID_PARAMETER;
  276. }
  277. NewRelativeName->MaximumLength =
  278. NewRelativeName->Length + sizeof(L'\0');
  279. NewRelativeName->Buffer =
  280. ALLOCATE_HEAP_COLD(NewRelativeName->MaximumLength, BlockTypeDataBuffer);
  281. if (NewRelativeName->Buffer == NULL) {
  282. if( !ARGUMENT_PRESENT( UnicodeName ) ) {
  283. RtlFreeUnicodeString(&UnicodeServerName);
  284. }
  285. return STATUS_INSUFF_SERVER_RESOURCES;
  286. }
  287. RtlZeroMemory(NewRelativeName->Buffer, NewRelativeName->MaximumLength);
  288. nextLocation = NewRelativeName->Buffer;
  289. //
  290. // Copy strings and characters to new relative name.
  291. //
  292. *nextLocation++ = L'$';
  293. *nextLocation++ = L'$';
  294. *nextLocation++ = L'\\';
  295. RtlCopyMemory(
  296. nextLocation,
  297. UnicodeServerName.Buffer,
  298. UnicodeServerName.Length
  299. );
  300. nextLocation += (UnicodeServerName.Length / sizeof(WCHAR));
  301. *nextLocation++ = L'\\';
  302. RtlCopyMemory(
  303. nextLocation,
  304. OldRelativeName.Buffer,
  305. OldRelativeName.Length
  306. );
  307. if( !ARGUMENT_PRESENT( UnicodeName ) ) {
  308. //
  309. // Free UnicodeServerName.
  310. //
  311. RtlFreeUnicodeString(&UnicodeServerName);
  312. }
  313. *Remapped = TRUE;
  314. return STATUS_SUCCESS;
  315. }
  316. NTSTATUS
  317. SrvCreateFile(
  318. IN OUT PWORK_CONTEXT WorkContext,
  319. IN USHORT SmbDesiredAccess,
  320. IN USHORT SmbFileAttributes,
  321. IN USHORT SmbOpenFunction,
  322. IN ULONG SmbAllocationSize,
  323. IN PCHAR SmbFileName,
  324. IN PCHAR EndOfSmbFileName,
  325. IN PVOID EaBuffer OPTIONAL,
  326. IN ULONG EaLength,
  327. OUT PULONG EaErrorOffset OPTIONAL,
  328. IN OPLOCK_TYPE RequestedOplockType,
  329. IN PRESTART_ROUTINE RestartRoutine
  330. )
  331. /*++
  332. Routine Description:
  333. Does most of the operations necessary to open or create a file.
  334. First the UID and TID are verified and the corresponding session and
  335. tree connect blocks located. The input file name name is
  336. canonicalized, and a fully qualified name is formed. An appropriate
  337. subroutine is called to do the open, based on whether this is a
  338. normal, compatibility mode, or FCB open.
  339. Arguments:
  340. WorkContext - Work context block for the operation.
  341. SmbDesiredAccess - The desired access in SMB protocol format.
  342. SmbFileAttributes - File attributes in SMB protocol format.
  343. SmbOpenFunction - Open function in SMB protocol format.
  344. SmbAllocationSize - Allocation size for new files.
  345. SmbFileName - A pointer to the zero-terminated file name in the
  346. request SMB. NOTE: This pointer should NOT point to the ASCII
  347. format indicator (\004) present in some SMBs!
  348. EndOfSmbFileName - a pointer to the last possible character that
  349. the file name can be in. If the name extands beyond this location
  350. without a zero terminator, SrvCanonicalizePathName will fail.
  351. EaBuffer - Optional pointer to a full EA list to pass to SrvIoCreateFile.
  352. EaLength - Length of the EA buffer.
  353. EaErrorOffset - Optional pointer to the location in which to write
  354. the offset to the EA that caused an error.
  355. Return Value:
  356. NTSTATUS - Indicates what occurred.
  357. --*/
  358. {
  359. NTSTATUS status;
  360. PMFCB mfcb;
  361. PNONPAGED_MFCB nonpagedMfcb;
  362. PRFCB rfcb;
  363. PSESSION session;
  364. PTREE_CONNECT treeConnect;
  365. UNICODE_STRING relativeName;
  366. UNICODE_STRING pipeRelativeName;
  367. BOOLEAN pipeRelativeNameAllocated = FALSE;
  368. UNICODE_STRING fullName;
  369. SHARE_TYPE shareType;
  370. ULONG error;
  371. ULONG jobId;
  372. ULONG hashValue;
  373. ULONG attributes;
  374. ULONG openRetries;
  375. BOOLEAN isUnicode;
  376. BOOLEAN caseInsensitive;
  377. PSRV_LOCK mfcbLock;
  378. //
  379. // NOTE ON MFCB REFERENCE COUNT HANDLING
  380. //
  381. // After finding or creating an MFCB for a file, we increment the
  382. // MFCB reference count an extra time to simplify our
  383. // synchronization logic. We hold the MfcbListLock lock while
  384. // finding/creating the MFCB, but release it after acquiring the the
  385. // per-MFCB lock. We then call one of the DoXxxOpen routines, which
  386. // may need to queue an LFCB to the MFCB and thus need to increment
  387. // the count. But they can't, because the MFCB list lock may not be
  388. // acquired while the per-MFCB lock is held because of deadlock
  389. // potential. The boolean LfcbAddedToMfcbList returned from the
  390. // routines indicates whether they actually queued an LFCB to the
  391. // MFCB. If they didn't, we need to release the extra reference.
  392. //
  393. // Note that it isn't often that we actually have to dereference the
  394. // MFCB. This only occurs when 1) the open fails, or 2) a
  395. // compatibility mode or FCB open succeeds when the client already
  396. // has the file open.
  397. //
  398. BOOLEAN lfcbAddedToMfcbList;
  399. PAGED_CODE( );
  400. //
  401. // Assume we won't need a temporary open.
  402. //
  403. WorkContext->Parameters2.Open.TemporaryOpen = FALSE;
  404. //
  405. // If a session block has not already been assigned to the current
  406. // work context, verify the UID. If verified, the address of the
  407. // session block corresponding to this user is stored in the
  408. // WorkContext block and the session block is referenced.
  409. //
  410. // Find the tree connect corresponding to the given TID if a tree
  411. // connect pointer has not already been put in the WorkContext block
  412. // by an AndX command or a previous call to SrvCreateFile.
  413. //
  414. status = SrvVerifyUidAndTid(
  415. WorkContext,
  416. &session,
  417. &treeConnect,
  418. ShareTypeWild
  419. );
  420. if ( !NT_SUCCESS(status) ) {
  421. IF_DEBUG(SMB_ERRORS) {
  422. KdPrint(( "SrvCreateFile: Invalid UID or TID\n" ));
  423. }
  424. return status;
  425. }
  426. //
  427. // If the session has expired, return that info
  428. //
  429. if( session->IsSessionExpired )
  430. {
  431. return SESSION_EXPIRED_STATUS_CODE;
  432. }
  433. //
  434. // Decide if we're case sensitive or not
  435. //
  436. caseInsensitive = (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE) ||
  437. session->UsingUppercasePaths;
  438. //
  439. // Here we begin share type specific processing.
  440. //
  441. shareType = treeConnect->Share->ShareType;
  442. //
  443. // If this operation may block, and we are running short of
  444. // free work items, fail this SMB with an out of resources error.
  445. // Note that a disk open will block if the file is currently oplocked.
  446. //
  447. if ( shareType == ShareTypeDisk && !WorkContext->BlockingOperation ) {
  448. if ( SrvReceiveBufferShortage( ) ) {
  449. SrvStatistics.BlockingSmbsRejected++;
  450. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  451. return STATUS_INSUFF_SERVER_RESOURCES;
  452. } else {
  453. //
  454. // SrvBlockingOpsInProgress has already been incremented.
  455. // Flag this work item as a blocking operation.
  456. //
  457. WorkContext->BlockingOperation = TRUE;
  458. }
  459. }
  460. isUnicode = SMB_IS_UNICODE( WorkContext );
  461. switch ( shareType ) {
  462. case ShareTypePrint:
  463. //
  464. // Allocate space to hold the file name we're going to open.
  465. //
  466. fullName.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
  467. fullName.Buffer = ALLOCATE_HEAP_COLD(
  468. fullName.MaximumLength,
  469. BlockTypeDataBuffer
  470. );
  471. if ( fullName.Buffer == NULL ) {
  472. return STATUS_INSUFF_SERVER_RESOURCES;
  473. }
  474. //
  475. // Get a print file name to use for spooling the request.
  476. // We open this as a disk file, use normal writes to get the
  477. // data, then call ScheduleJob( ) in XACTSRV to start the
  478. // actual printing process.
  479. //
  480. status = SrvAddPrintJob(
  481. WorkContext,
  482. WorkContext->TreeConnect->Share->Type.hPrinter,
  483. &fullName,
  484. &jobId,
  485. &error
  486. );
  487. if ( !NT_SUCCESS(status) ) {
  488. IF_DEBUG(SMB_ERRORS) {
  489. KdPrint(( "SrvCreateFile: SrvAddPrintJob failed: %lx (%ld)\n",
  490. status, error ));
  491. }
  492. FREE_HEAP( fullName.Buffer );
  493. if ( error != NO_ERROR ) {
  494. ASSERT( SrvErrorCode(error) == error );
  495. status = (NTSTATUS)(SRV_WIN32_STATUS | error);
  496. }
  497. return status;
  498. }
  499. //
  500. // Scan the Master File Table to see if the named file is already
  501. // open.
  502. //
  503. mfcb = SrvFindMfcb( &fullName, caseInsensitive, &mfcbLock, &hashValue, WorkContext );
  504. if ( mfcb == NULL ) {
  505. //
  506. // There is no MFCB for this file. Create one.
  507. //
  508. mfcb = SrvCreateMfcb( &fullName, WorkContext, hashValue );
  509. if ( mfcb == NULL ) {
  510. //
  511. // Failure to add open file instance to MFT.
  512. //
  513. if( mfcbLock ) {
  514. RELEASE_LOCK( mfcbLock );
  515. }
  516. IF_DEBUG(ERRORS) {
  517. KdPrint(( "SrvCreateFile: Unable to allocate MFCB\n" ));
  518. }
  519. FREE_HEAP( fullName.Buffer );
  520. //
  521. // Free up the Job ID.
  522. //
  523. SrvSchedulePrintJob(
  524. WorkContext->TreeConnect->Share->Type.hPrinter,
  525. jobId
  526. );
  527. return STATUS_INSUFF_SERVER_RESOURCES;
  528. }
  529. }
  530. //
  531. // Increment the MFCB reference count. See the note at the beginning of this routine.
  532. //
  533. mfcb->BlockHeader.ReferenceCount++;
  534. UPDATE_REFERENCE_HISTORY( mfcb, FALSE );
  535. //
  536. // Grab the MFCB-based lock to serialize opens of the same file
  537. // and release the MFCB list lock.
  538. //
  539. nonpagedMfcb = mfcb->NonpagedMfcb;
  540. RELEASE_LOCK( mfcbLock );
  541. ACQUIRE_LOCK( &nonpagedMfcb->Lock );
  542. //
  543. // Set up the share access and desired access in SMB terms.
  544. // We will only write to the file, so just request write
  545. // as the desired access. As an optimization, the spooler
  546. // may read from the file before we finish writing to it,
  547. // so allow other readers.
  548. //
  549. SmbDesiredAccess = SMB_DA_ACCESS_WRITE | SMB_DA_SHARE_DENY_WRITE | SMB_LR_SEQUENTIAL;
  550. //
  551. // Set up the open function to create the file it it doesn't
  552. // exist and to truncate it if it does exist. There shouldn't
  553. // be preexisting data in the file, hence the truncation.
  554. //
  555. // !!! The spooler may change to create the file for us, in which
  556. // case this should change to only truncate.
  557. SmbOpenFunction = SMB_OFUN_CREATE_CREATE | SMB_OFUN_OPEN_TRUNCATE;
  558. //
  559. // This is a normal sharing mode open. Do the actual open
  560. // of the disk file.
  561. //
  562. status = DoNormalOpen(
  563. &rfcb,
  564. mfcb,
  565. WorkContext,
  566. &WorkContext->Irp->IoStatus,
  567. SmbDesiredAccess,
  568. SmbFileAttributes,
  569. SmbOpenFunction,
  570. SmbAllocationSize,
  571. &fullName,
  572. NULL,
  573. 0,
  574. 0,
  575. &lfcbAddedToMfcbList,
  576. RequestedOplockType
  577. );
  578. //
  579. // If the open worked, set up the Job ID in the LFCB.
  580. //
  581. if ( NT_SUCCESS(status) ) {
  582. rfcb->Lfcb->JobId = jobId;
  583. } else {
  584. //
  585. // Free up the Job ID if the open failed.
  586. //
  587. SrvSchedulePrintJob(
  588. WorkContext->TreeConnect->Share->Type.hPrinter,
  589. jobId
  590. );
  591. }
  592. //
  593. // Release the Open serialization lock and dereference the MFCB.
  594. //
  595. RELEASE_LOCK( &nonpagedMfcb->Lock );
  596. //
  597. // If DoNormalOpen didn't queue an LFCB to the MFCB, release the
  598. // extra reference that we added.
  599. //
  600. if ( !lfcbAddedToMfcbList ) {
  601. SrvDereferenceMfcb( mfcb );
  602. }
  603. SrvDereferenceMfcb( mfcb );
  604. //
  605. // Deallocate the full path name buffer.
  606. //
  607. FREE_HEAP( fullName.Buffer );
  608. break;
  609. case ShareTypeDisk:
  610. case ShareTypePipe:
  611. //
  612. // Canonicalize the path name so that it conforms to NT
  613. // standards.
  614. //
  615. // *** Note that this operation allocates space for the name.
  616. // This space is deallocated after the DoXxxOpen routine
  617. // returns.
  618. //
  619. status = SrvCanonicalizePathName(
  620. WorkContext,
  621. treeConnect->Share,
  622. NULL,
  623. SmbFileName,
  624. EndOfSmbFileName,
  625. TRUE,
  626. isUnicode,
  627. &relativeName
  628. );
  629. if( !NT_SUCCESS( status ) ) {
  630. //
  631. // The path tried to do ..\ to get beyond the share it has
  632. // accessed.
  633. //
  634. IF_DEBUG(ERRORS) {
  635. KdPrint(( "SrvCreateFile: Invalid pathname: %s\n",
  636. SmbFileName ));
  637. }
  638. return status;
  639. }
  640. //
  641. // Form the fully qualified name of the file.
  642. //
  643. // *** Note that this operation allocates space for the name.
  644. // This space is deallocated after the DoXxxOpen routine
  645. // returns.
  646. //
  647. if ( shareType == ShareTypeDisk ) {
  648. #ifdef SLMDBG
  649. if ( SrvIsSlmStatus( &relativeName ) &&
  650. SrvIsSlmAccessDisallowed(
  651. &relativeName,
  652. treeConnect->Share->RootDirectoryHandle
  653. ) ) {
  654. return STATUS_ACCESS_DENIED;
  655. }
  656. #endif
  657. SrvAllocateAndBuildPathName(
  658. &treeConnect->Share->DosPathName,
  659. &relativeName,
  660. NULL,
  661. &fullName
  662. );
  663. } else {
  664. UNICODE_STRING pipePrefix;
  665. RtlInitUnicodeString( &pipePrefix, StrSlashPipeSlash );
  666. //
  667. // Check for PIPE pathname prefix.
  668. //
  669. if ( !RtlPrefixUnicodeString(
  670. &SrvCanonicalNamedPipePrefix,
  671. &relativeName,
  672. TRUE
  673. ) ) {
  674. IF_DEBUG(SMB_ERRORS) {
  675. KdPrint(( "SrvCreateFile: Invalid pipe pathname: %s\n",
  676. SmbFileName ));
  677. }
  678. if ( !isUnicode ) {
  679. RtlFreeUnicodeString( &relativeName );
  680. }
  681. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  682. }
  683. //
  684. // Delete PIPE\ prefix from file path
  685. //
  686. pipeRelativeName.Buffer = (PWSTR)( (PCHAR)relativeName.Buffer +
  687. SrvCanonicalNamedPipePrefix.Length );
  688. pipeRelativeName.Length = relativeName.Length -
  689. SrvCanonicalNamedPipePrefix.Length;
  690. pipeRelativeName.MaximumLength = pipeRelativeName.Length;
  691. if( WorkContext->Endpoint->RemapPipeNames || treeConnect->RemapPipeNames ) {
  692. //
  693. // The RemapPipeNames flag is set, so remap the pipe name
  694. // to "$$\<server>\<pipe name>".
  695. //
  696. // Note: this operation allocates space for pipeRelativeName.
  697. //
  698. status = RemapPipeName(
  699. &WorkContext->Endpoint->TransportAddress,
  700. treeConnect->RemapPipeNames ? &treeConnect->ServerName : NULL ,
  701. &pipeRelativeName,
  702. &pipeRelativeNameAllocated
  703. );
  704. if( !NT_SUCCESS( status ) ) {
  705. if ( !isUnicode ) {
  706. RtlFreeUnicodeString( &relativeName );
  707. }
  708. return status;
  709. }
  710. }
  711. SrvAllocateAndBuildPathName(
  712. &pipePrefix,
  713. &pipeRelativeName,
  714. NULL,
  715. &fullName
  716. );
  717. //
  718. // If this is a compatibility mode or FCB mode open, map
  719. // it to a normal non-shared open.
  720. //
  721. if ( SmbDesiredAccess == SMB_DA_FCB_MASK ||
  722. (SmbDesiredAccess & SMB_DA_SHARE_MASK) ==
  723. SMB_DA_SHARE_COMPATIBILITY ) {
  724. SmbDesiredAccess = SMB_DA_ACCESS_READ_WRITE |
  725. SMB_DA_SHARE_EXCLUSIVE;
  726. }
  727. }
  728. if ( fullName.Buffer == NULL ) {
  729. //
  730. // Unable to allocate heap for the full name.
  731. //
  732. IF_DEBUG(ERRORS) {
  733. KdPrint(( "SrvCreateFile: Unable to allocate heap for "
  734. "full path name\n" ));
  735. }
  736. if ( !isUnicode ) {
  737. RtlFreeUnicodeString( &relativeName );
  738. }
  739. if( pipeRelativeNameAllocated ) {
  740. FREE_HEAP( pipeRelativeName.Buffer );
  741. }
  742. return STATUS_INSUFF_SERVER_RESOURCES;
  743. }
  744. attributes = caseInsensitive ? OBJ_CASE_INSENSITIVE : 0;
  745. if ( WorkContext->ProcessingCount == 2) {
  746. HANDLE fileHandle;
  747. OBJECT_ATTRIBUTES objectAttributes;
  748. IO_STATUS_BLOCK ioStatusBlock;
  749. //
  750. // This is the second time through, so we must be in a blocking
  751. // thread. Do a blocking open of the file to force an oplock
  752. // break. Then close the handle and fall through to the normal
  753. // open path.
  754. //
  755. // We must do the blocking open without holding the MFCB
  756. // lock, because this lock can be acquired during oplock
  757. // break, resulting in deadlock.
  758. //
  759. SrvInitializeObjectAttributes_U(
  760. &objectAttributes,
  761. &relativeName,
  762. attributes,
  763. NULL,
  764. NULL
  765. );
  766. status = SrvIoCreateFile(
  767. WorkContext,
  768. &fileHandle,
  769. GENERIC_READ,
  770. &objectAttributes,
  771. &ioStatusBlock,
  772. NULL,
  773. 0,
  774. FILE_SHARE_VALID_FLAGS,
  775. FILE_OPEN,
  776. 0,
  777. NULL,
  778. 0,
  779. CreateFileTypeNone,
  780. NULL, // ExtraCreateParameters
  781. 0,
  782. WorkContext->TreeConnect->Share
  783. );
  784. if ( NT_SUCCESS( status ) ) {
  785. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 9, 0 );
  786. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 16, 0 );
  787. SrvNtClose( fileHandle, TRUE );
  788. }
  789. }
  790. //
  791. // Scan the Master File Table to see if the named file is already
  792. // open. We can do the scan with a shared lock, but we must have an
  793. // exclusive lock to modify the table. Start out shared, assuming the
  794. // file is already open.
  795. //
  796. mfcb = SrvFindMfcb( &fullName, caseInsensitive, &mfcbLock, &hashValue, WorkContext );
  797. if ( mfcb == NULL ) {
  798. //
  799. // There is no MFCB for this file. Create one.
  800. //
  801. mfcb = SrvCreateMfcb( &fullName, WorkContext, hashValue );
  802. if ( mfcb == NULL ) {
  803. //
  804. // Failure to add open file instance to MFT.
  805. //
  806. if( mfcbLock ) {
  807. RELEASE_LOCK( mfcbLock );
  808. }
  809. IF_DEBUG(ERRORS) {
  810. KdPrint(( "SrvCreateFile: Unable to allocate MFCB\n" ));
  811. }
  812. FREE_HEAP( fullName.Buffer );
  813. if ( !isUnicode ) {
  814. RtlFreeUnicodeString( &relativeName );
  815. }
  816. if( pipeRelativeNameAllocated ) {
  817. FREE_HEAP( pipeRelativeName.Buffer );
  818. }
  819. return STATUS_INSUFF_SERVER_RESOURCES;
  820. }
  821. }
  822. //
  823. // Increment the MFCB reference count. See the note at the beginning of this routine.
  824. //
  825. mfcb->BlockHeader.ReferenceCount++;
  826. UPDATE_REFERENCE_HISTORY( mfcb, FALSE );
  827. //
  828. // Grab the MFCB-based lock to serialize opens of the same file
  829. // and release the MFCB list lock.
  830. //
  831. nonpagedMfcb = mfcb->NonpagedMfcb;
  832. RELEASE_LOCK( mfcbLock );
  833. ACQUIRE_LOCK( &nonpagedMfcb->Lock );
  834. //
  835. // Call an appropriate routine to actually do the open.
  836. //
  837. openRetries = SrvSharingViolationRetryCount;
  838. start_retry:
  839. if ( SmbDesiredAccess == SMB_DA_FCB_MASK ) {
  840. //
  841. // This is an FCB open.
  842. //
  843. status = DoFcbOpen(
  844. &rfcb,
  845. mfcb,
  846. WorkContext,
  847. &WorkContext->Irp->IoStatus,
  848. SmbFileAttributes,
  849. SmbOpenFunction,
  850. SmbAllocationSize,
  851. &relativeName,
  852. EaBuffer,
  853. EaLength,
  854. EaErrorOffset,
  855. &lfcbAddedToMfcbList
  856. );
  857. } else if ( (SmbDesiredAccess & SMB_DA_SHARE_MASK) ==
  858. SMB_DA_SHARE_COMPATIBILITY ) {
  859. //
  860. // This is a compatibility mode open.
  861. //
  862. status = DoCompatibilityOpen(
  863. &rfcb,
  864. mfcb,
  865. WorkContext,
  866. &WorkContext->Irp->IoStatus,
  867. SmbDesiredAccess,
  868. SmbFileAttributes,
  869. SmbOpenFunction,
  870. SmbAllocationSize,
  871. &relativeName,
  872. EaBuffer,
  873. EaLength,
  874. EaErrorOffset,
  875. &lfcbAddedToMfcbList,
  876. RequestedOplockType
  877. );
  878. } else {
  879. //
  880. // This is a normal sharing mode open.
  881. //
  882. status = DoNormalOpen(
  883. &rfcb,
  884. mfcb,
  885. WorkContext,
  886. &WorkContext->Irp->IoStatus,
  887. SmbDesiredAccess,
  888. SmbFileAttributes,
  889. SmbOpenFunction,
  890. SmbAllocationSize,
  891. shareType == ShareTypePipe ?
  892. &pipeRelativeName : &relativeName,
  893. EaBuffer,
  894. EaLength,
  895. EaErrorOffset,
  896. &lfcbAddedToMfcbList,
  897. RequestedOplockType
  898. );
  899. }
  900. //
  901. // Retry if sharing violation and we are in the blocking thread.
  902. //
  903. if ( (WorkContext->ProcessingCount == 2) &&
  904. (status == STATUS_SHARING_VIOLATION) &&
  905. (shareType == ShareTypeDisk) &&
  906. (openRetries-- > 0) ) {
  907. //
  908. // Release the mfcb lock so that a close might slip through.
  909. //
  910. RELEASE_LOCK( &nonpagedMfcb->Lock );
  911. (VOID) KeDelayExecutionThread(
  912. KernelMode,
  913. FALSE,
  914. &SrvSharingViolationDelay
  915. );
  916. ACQUIRE_LOCK( &nonpagedMfcb->Lock );
  917. goto start_retry;
  918. }
  919. //
  920. // Release the Open serialization lock and dereference the MFCB.
  921. //
  922. RELEASE_LOCK( &nonpagedMfcb->Lock );
  923. //
  924. // If DoXxxOpen didn't queue an LFCB to the MFCB, release the
  925. // extra reference that we added.
  926. //
  927. if ( !lfcbAddedToMfcbList ) {
  928. SrvDereferenceMfcb( mfcb );
  929. }
  930. SrvDereferenceMfcb( mfcb );
  931. //
  932. // Deallocate the full path name buffer.
  933. //
  934. FREE_HEAP( fullName.Buffer );
  935. if ( !isUnicode ) {
  936. RtlFreeUnicodeString( &relativeName );
  937. }
  938. break;
  939. //
  940. // Default case, illegal device type. This should never happen.
  941. //
  942. default:
  943. // !!! Is this an appropriate error return code? Probably no.
  944. status = STATUS_INVALID_PARAMETER;
  945. rfcb = NULL;
  946. }
  947. //
  948. // Update the statistics database if the open was successful.
  949. //
  950. if ( NT_SUCCESS(status) ) {
  951. SrvStatistics.TotalFilesOpened++;
  952. }
  953. //
  954. // Make a pointer to the RFCB accessible to the caller.
  955. //
  956. WorkContext->Parameters2.Open.Rfcb = rfcb;
  957. //
  958. // If there is an oplock break in progress, wait for the oplock
  959. // break to complete.
  960. //
  961. if ( status == STATUS_OPLOCK_BREAK_IN_PROGRESS ) {
  962. NTSTATUS startStatus;
  963. //
  964. // Save the Information from the open, so it doesn't
  965. // get lost when we re-use the WorkContext->Irp for the
  966. // oplock processing.
  967. //
  968. WorkContext->Parameters2.Open.IosbInformation = WorkContext->Irp->IoStatus.Information;
  969. startStatus = SrvStartWaitForOplockBreak(
  970. WorkContext,
  971. RestartRoutine,
  972. 0,
  973. rfcb->Lfcb->FileObject
  974. );
  975. if (!NT_SUCCESS( startStatus ) ) {
  976. //
  977. // The file is oplocked, and we cannot wait for the oplock
  978. // break to complete. Just close the file, and return the
  979. // error.
  980. //
  981. SrvCloseRfcb( rfcb );
  982. status = startStatus;
  983. }
  984. }
  985. if( pipeRelativeNameAllocated ) {
  986. FREE_HEAP( pipeRelativeName.Buffer );
  987. }
  988. //
  989. // Return the open status.
  990. //
  991. return status;
  992. } // SrvCreateFile
  993. NTSTATUS
  994. DoNormalOpen(
  995. OUT PRFCB *Rfcb,
  996. IN PMFCB Mfcb,
  997. IN OUT PWORK_CONTEXT WorkContext,
  998. OUT PIO_STATUS_BLOCK IoStatusBlock,
  999. IN USHORT SmbDesiredAccess,
  1000. IN USHORT SmbFileAttributes,
  1001. IN USHORT SmbOpenFunction,
  1002. IN ULONG SmbAllocationSize,
  1003. IN PUNICODE_STRING RelativeName,
  1004. IN PVOID EaBuffer OPTIONAL,
  1005. IN ULONG EaLength,
  1006. OUT PULONG EaErrorOffset OPTIONAL,
  1007. OUT PBOOLEAN LfcbAddedToMfcbList,
  1008. IN OPLOCK_TYPE RequestedOplockType
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. Processes a normal sharing mode open.
  1013. *** The MFCB lock must be held on entry to this routine; the lock
  1014. remains held on exit.
  1015. Arguments:
  1016. Rfcb - A pointer to a pointer to an RFCB that will point to the
  1017. newly-created RFCB.
  1018. Mfcb - A pointer to the MFCB for this file.
  1019. WorkContext - Work context block for the operation.
  1020. IoStatusBlock - A pointer to an IO status block.
  1021. SmbDesiredAccess - The desired access in SMB protocol format.
  1022. SmbFileAttributes - File attributes in SMB protocol format.
  1023. SmbOpenFunction - Open function in SMB protocol format.
  1024. SmbAllocationSize - Allocation size for new files.
  1025. RelativeName - The share-relative name of the file being opened.
  1026. EaBuffer - Optional pointer to a full EA list to pass to SrvIoCreateFile.
  1027. EaLength - Length of the EA buffer.
  1028. EaErrorOffset - Optional pointer to the location in which to write
  1029. the offset to the EA that caused an error.
  1030. LfcbAddedToMfcbList - Pointer to a boolean that will be set to TRUE if
  1031. an lfcb is added to the mfcb list of lfcbs. FALSE, otherwise.
  1032. Return Value:
  1033. NTSTATUS - Indicates what occurred.
  1034. --*/
  1035. {
  1036. NTSTATUS status;
  1037. NTSTATUS completionStatus;
  1038. HANDLE fileHandle;
  1039. OBJECT_ATTRIBUTES objectAttributes;
  1040. ULONG attributes;
  1041. LARGE_INTEGER allocationSize;
  1042. ULONG fileAttributes;
  1043. BOOLEAN directory;
  1044. ULONG shareAccess;
  1045. ULONG createDisposition;
  1046. ULONG createOptions;
  1047. ACCESS_MASK desiredAccess;
  1048. PSHARE fileShare = NULL;
  1049. UCHAR errorClass = SMB_ERR_CLASS_DOS;
  1050. USHORT error = 0;
  1051. PAGED_CODE( );
  1052. *LfcbAddedToMfcbList = FALSE;
  1053. //
  1054. // Map the desired access from SMB terms to NT terms.
  1055. //
  1056. status = MapDesiredAccess( SmbDesiredAccess, &desiredAccess );
  1057. if ( !NT_SUCCESS(status) ) {
  1058. return status;
  1059. }
  1060. #ifdef SLMDBG
  1061. if ( SrvIsSlmStatus( RelativeName ) ||
  1062. SrvIsTempSlmStatus( RelativeName ) ) {
  1063. desiredAccess |= GENERIC_READ;
  1064. }
  1065. #endif
  1066. //
  1067. // Map the share mode from SMB terms to NT terms.
  1068. //
  1069. status = MapShareAccess( SmbDesiredAccess, &shareAccess );
  1070. if ( !NT_SUCCESS(status) ) {
  1071. return status;
  1072. }
  1073. //
  1074. // We're going to open this file relative to the root directory
  1075. // of the share. Load up the necessary fields in the object
  1076. // attributes structure.
  1077. //
  1078. if ( WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ) {
  1079. attributes = OBJ_CASE_INSENSITIVE;
  1080. } else if ( WorkContext->Session->UsingUppercasePaths ) {
  1081. attributes = OBJ_CASE_INSENSITIVE;
  1082. } else {
  1083. attributes = 0L;
  1084. }
  1085. if ( WorkContext->TreeConnect->Share->ShareType == ShareTypePipe ) {
  1086. SrvInitializeObjectAttributes_U(
  1087. &objectAttributes,
  1088. RelativeName,
  1089. attributes,
  1090. SrvNamedPipeHandle,
  1091. NULL
  1092. );
  1093. } else {
  1094. fileShare = WorkContext->TreeConnect->Share;
  1095. SrvInitializeObjectAttributes_U(
  1096. &objectAttributes,
  1097. RelativeName,
  1098. attributes,
  1099. NULL,
  1100. NULL
  1101. );
  1102. }
  1103. //
  1104. // Set block size according to the AllocationSize in the request SMB.
  1105. //
  1106. allocationSize.QuadPart = SmbAllocationSize;
  1107. //
  1108. // Get the value for fileAttributes.
  1109. //
  1110. SRV_SMB_ATTRIBUTES_TO_NT(
  1111. SmbFileAttributes,
  1112. &directory,
  1113. &fileAttributes
  1114. );
  1115. //
  1116. // Set createDisposition parameter from OpenFunction.
  1117. //
  1118. status = MapOpenFunction( SmbOpenFunction, &createDisposition );
  1119. //
  1120. // OS/2 expects that if it creates a file with an allocation size,
  1121. // the end of file pointer will be the same as that allocation size.
  1122. // Therefore, the server is expected to set EOF to the allocation
  1123. // size on creating a file. However, this requires write access,
  1124. // so if the client is creating a file with an allocation size, give
  1125. // him write access. Only do this if creating a file; if this is
  1126. // a "create or open" operation, don't do this, as it could cause
  1127. // an extraneuos audit.
  1128. //
  1129. if ( SmbAllocationSize != 0 && createDisposition == FILE_CREATE ) {
  1130. desiredAccess |= GENERIC_WRITE;
  1131. }
  1132. //
  1133. // Set createOptions parameter.
  1134. //
  1135. if ( SmbDesiredAccess & SMB_DA_WRITE_THROUGH ) {
  1136. createOptions = FILE_WRITE_THROUGH | FILE_NON_DIRECTORY_FILE;
  1137. } else {
  1138. createOptions = FILE_NON_DIRECTORY_FILE;
  1139. }
  1140. if ( (SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 ) &
  1141. SMB_FLAGS2_KNOWS_EAS) == 0) {
  1142. //
  1143. // This guy does not know eas
  1144. //
  1145. createOptions |= FILE_NO_EA_KNOWLEDGE;
  1146. }
  1147. //
  1148. // Set the caching hints flags.
  1149. //
  1150. status = MapCacheHints( SmbDesiredAccess, &createOptions );
  1151. //
  1152. // Check to see if there is a cached handle for the file.
  1153. //
  1154. if ( (createDisposition == FILE_OPEN) ||
  1155. (createDisposition == FILE_CREATE) ||
  1156. (createDisposition == FILE_OPEN_IF) ) {
  1157. ASSERT( *LfcbAddedToMfcbList == FALSE );
  1158. IF_DEBUG(FILE_CACHE) {
  1159. KdPrint(( "SrvCreateFile: checking for cached rfcb for %wZ\n", RelativeName ));
  1160. }
  1161. if ( SrvFindCachedRfcb(
  1162. WorkContext,
  1163. Mfcb,
  1164. desiredAccess,
  1165. shareAccess,
  1166. createDisposition,
  1167. createOptions,
  1168. RequestedOplockType,
  1169. &status ) ) {
  1170. IF_DEBUG(FILE_CACHE) {
  1171. KdPrint(( "SrvCreateFile: FindCachedRfcb = TRUE, status = %x, rfcb = %p\n",
  1172. status, WorkContext->Rfcb ));
  1173. }
  1174. IoStatusBlock->Information = FILE_OPENED;
  1175. return status;
  1176. }
  1177. IF_DEBUG(FILE_CACHE) {
  1178. KdPrint(( "SrvCreateFile: FindCachedRfcb = FALSE; do it the slow way\n" ));
  1179. }
  1180. }
  1181. //
  1182. // Call SrvIoCreateFile to create or open the file. (We call
  1183. // SrvIoCreateFile, rather than NtOpenFile, in order to get user-mode
  1184. // access checking.)
  1185. //
  1186. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1187. KdPrint(( "DoNormalOpen: Opening file %wZ\n", RelativeName ));
  1188. }
  1189. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1190. //
  1191. // Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
  1192. // component, the Io subsystem does not check it for us.
  1193. //
  1194. if( ARGUMENT_PRESENT( EaBuffer ) ) {
  1195. status = IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION)EaBuffer, EaLength, EaErrorOffset );
  1196. } else {
  1197. status = STATUS_SUCCESS;
  1198. }
  1199. if( NT_SUCCESS( status ) ) {
  1200. createOptions |= FILE_COMPLETE_IF_OPLOCKED;
  1201. status = SrvIoCreateFile(
  1202. WorkContext,
  1203. &fileHandle,
  1204. desiredAccess,
  1205. &objectAttributes,
  1206. IoStatusBlock,
  1207. &allocationSize,
  1208. fileAttributes,
  1209. shareAccess,
  1210. createDisposition,
  1211. createOptions,
  1212. EaBuffer,
  1213. EaLength,
  1214. CreateFileTypeNone,
  1215. NULL, // ExtraCreateParameters
  1216. IO_FORCE_ACCESS_CHECK,
  1217. fileShare
  1218. );
  1219. }
  1220. //
  1221. // If we got sharing violation and this is a disk file, and this is
  1222. // the first open attempt, setup for a blocking open attempt. If the
  1223. // file is batch oplocked, the non-blocking open would fail, and the
  1224. // oplock will not break.
  1225. //
  1226. if ( status == STATUS_SHARING_VIOLATION &&
  1227. WorkContext->ProcessingCount == 1 &&
  1228. WorkContext->TreeConnect->Share->ShareType == ShareTypeDisk ) {
  1229. WorkContext->Parameters2.Open.TemporaryOpen = TRUE;
  1230. }
  1231. //
  1232. // If the user didn't have this permission, update the statistics
  1233. // database.
  1234. //
  1235. if ( status == STATUS_ACCESS_DENIED ) {
  1236. SrvStatistics.AccessPermissionErrors++;
  1237. }
  1238. if ( !NT_SUCCESS(status) ) {
  1239. //
  1240. // The open failed.
  1241. //
  1242. IF_DEBUG(ERRORS) {
  1243. KdPrint(( "DoNormalOpen: SrvIoCreateFile failed, file = %wZ, status = %X, Info = 0x%p\n",
  1244. objectAttributes.ObjectName,
  1245. status, (PVOID)IoStatusBlock->Information ));
  1246. }
  1247. //
  1248. // Set the error offset if needed.
  1249. //
  1250. if ( ARGUMENT_PRESENT(EaErrorOffset) &&
  1251. status == STATUS_INVALID_EA_NAME ) {
  1252. *EaErrorOffset = (ULONG)IoStatusBlock->Information;
  1253. IoStatusBlock->Information = 0;
  1254. }
  1255. return status;
  1256. }
  1257. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 10, 0 );
  1258. //
  1259. // The open was successful. Attempt to allocate structures to
  1260. // represent the open. If any errors occur, CompleteOpen does full
  1261. // cleanup, including closing the file.
  1262. //
  1263. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1264. KdPrint(( "DoNormalOpen: Open of %wZ succeeded, file handle: 0x%p\n",
  1265. RelativeName, fileHandle ));
  1266. }
  1267. completionStatus = CompleteOpen(
  1268. Rfcb,
  1269. Mfcb,
  1270. WorkContext,
  1271. NULL,
  1272. fileHandle,
  1273. NULL,
  1274. shareAccess,
  1275. createOptions,
  1276. FALSE,
  1277. FALSE,
  1278. LfcbAddedToMfcbList
  1279. );
  1280. //
  1281. // Return the "interesting" status code. If CompleteOpen() succeeds
  1282. // return the open status. If it fails, it will clean up the open
  1283. // file, and we return a failure status.
  1284. //
  1285. if ( !NT_SUCCESS( completionStatus ) ) {
  1286. return completionStatus;
  1287. } else {
  1288. return status;
  1289. }
  1290. } // DoNormalOpen
  1291. NTSTATUS
  1292. DoCompatibilityOpen(
  1293. OUT PRFCB *Rfcb,
  1294. IN PMFCB Mfcb,
  1295. IN OUT PWORK_CONTEXT WorkContext,
  1296. OUT PIO_STATUS_BLOCK IoStatusBlock,
  1297. IN USHORT SmbDesiredAccess,
  1298. IN USHORT SmbFileAttributes,
  1299. IN USHORT SmbOpenFunction,
  1300. IN ULONG SmbAllocationSize,
  1301. IN PUNICODE_STRING RelativeName,
  1302. IN PVOID EaBuffer OPTIONAL,
  1303. IN ULONG EaLength,
  1304. OUT PULONG EaErrorOffset OPTIONAL,
  1305. OUT PBOOLEAN LfcbAddedToMfcbList,
  1306. IN OPLOCK_TYPE RequestedOplockType
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. Processes a compatibility mode open.
  1311. *** The MFCB lock must be held on entry to this routine; the lock
  1312. remains held on exit.
  1313. Arguments:
  1314. Rfcb - A pointer to a pointer to an RFCB that will point to the
  1315. newly-created RFCB.
  1316. Mfcb - A pointer to the MFCB for this file.
  1317. WorkContext - Work context block for the operation.
  1318. IoStatusBlock - A pointer to an IO status block.
  1319. SmbDesiredAccess - The desired access in SMB protocol format.
  1320. SmbFileAttributes - File attributes in SMB protocol format.
  1321. SmbOpenFunction - Open function in SMB protocol format.
  1322. SmbAllocationSize - Allocation size for new files.
  1323. RelativeName - The share-relative name of the file being opened.
  1324. EaBuffer - Optional pointer to a full EA list to pass to SrvIoCreateFile.
  1325. EaLength - Length of the EA buffer.
  1326. EaErrorOffset - Optional pointer to the location in which to write
  1327. the offset to the EA that caused an error.
  1328. LfcbAddedToMfcbList - Pointer to a boolean that will be set to TRUE if
  1329. an lfcb is added to the mfcb list of lfcbs.
  1330. Return Value:
  1331. NTSTATUS - Indicates what occurred.
  1332. --*/
  1333. {
  1334. NTSTATUS status;
  1335. NTSTATUS completionStatus;
  1336. PLFCB lfcb;
  1337. HANDLE fileHandle;
  1338. OBJECT_ATTRIBUTES objectAttributes;
  1339. ULONG attributes;
  1340. LARGE_INTEGER allocationSize;
  1341. ULONG fileAttributes;
  1342. BOOLEAN directory;
  1343. ULONG createDisposition;
  1344. ULONG createOptions;
  1345. ACCESS_MASK desiredAccess;
  1346. USHORT smbOpenMode;
  1347. PAGED_CODE( );
  1348. *LfcbAddedToMfcbList = FALSE;
  1349. //
  1350. // Map the desired access from SMB terms to NT terms.
  1351. //
  1352. status = MapDesiredAccess( SmbDesiredAccess, &desiredAccess );
  1353. if ( !NT_SUCCESS(status) ) {
  1354. return status;
  1355. }
  1356. //
  1357. // Set createDisposition parameter from OpenFunction.
  1358. //
  1359. status = MapOpenFunction( SmbOpenFunction, &createDisposition );
  1360. if ( !NT_SUCCESS(status) ) {
  1361. return status;
  1362. }
  1363. //
  1364. // Set createOptions parameter.
  1365. //
  1366. if ( SmbDesiredAccess & SMB_DA_WRITE_THROUGH ) {
  1367. createOptions = FILE_WRITE_THROUGH | FILE_NON_DIRECTORY_FILE;
  1368. } else {
  1369. createOptions = FILE_NON_DIRECTORY_FILE;
  1370. }
  1371. if ( (SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 ) &
  1372. SMB_FLAGS2_KNOWS_EAS) == 0) {
  1373. //
  1374. // This guy does not know eas
  1375. //
  1376. createOptions |= FILE_NO_EA_KNOWLEDGE;
  1377. }
  1378. //
  1379. // We're going to open this file relative to the root directory
  1380. // of the share. Load up the necessary fields in the object
  1381. // attributes structure.
  1382. //
  1383. if ( WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ) {
  1384. attributes = OBJ_CASE_INSENSITIVE;
  1385. } else if ( WorkContext->Session->UsingUppercasePaths ) {
  1386. attributes = OBJ_CASE_INSENSITIVE;
  1387. } else {
  1388. attributes = 0L;
  1389. }
  1390. SrvInitializeObjectAttributes_U(
  1391. &objectAttributes,
  1392. RelativeName,
  1393. attributes,
  1394. NULL,
  1395. NULL
  1396. );
  1397. if ( Mfcb->ActiveRfcbCount > 0 ) {
  1398. //
  1399. // The named file is already opened by the server. If the client
  1400. // specified that it didn't want to open an existing file,
  1401. // reject this open.
  1402. //
  1403. if ( createDisposition == FILE_CREATE ) {
  1404. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1405. KdPrint(( "DoCompatibilityOpen: Compatibility open of %wZ rejected; wants to create\n", RelativeName ));
  1406. }
  1407. return STATUS_OBJECT_NAME_COLLISION;
  1408. }
  1409. //
  1410. // If the existing open is not a compatibility mode open, then
  1411. // we try to map the new open into a normal sharing mode. If
  1412. // that works, we attempt a normal open. If it doesn't work, we
  1413. // reject the new open. If the existing open is a compatibility
  1414. // mode open by this session, we just add a new RFCB. If it's a
  1415. // compatibility mode open by a different session, we reject
  1416. // this open.
  1417. //
  1418. if ( !Mfcb->CompatibilityOpen ) {
  1419. //
  1420. // The named file is open, but not in compatibility mode.
  1421. // Determine whether this should be mapped from a
  1422. // compatibility mode open to a normal sharing mode open.
  1423. //
  1424. smbOpenMode = SmbDesiredAccess;
  1425. if ( MapCompatibilityOpen( RelativeName, &smbOpenMode ) ) {
  1426. //
  1427. // The open has been mapped to a normal sharing mode.
  1428. //
  1429. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1430. KdPrint(( "DoCompatibilityOpen: Mapped compatibility open of %wZ to normal open\n", RelativeName ));
  1431. }
  1432. return DoNormalOpen(
  1433. Rfcb,
  1434. Mfcb,
  1435. WorkContext,
  1436. IoStatusBlock,
  1437. smbOpenMode,
  1438. SmbFileAttributes,
  1439. SmbOpenFunction,
  1440. SmbAllocationSize,
  1441. RelativeName,
  1442. EaBuffer,
  1443. EaLength,
  1444. EaErrorOffset,
  1445. LfcbAddedToMfcbList,
  1446. RequestedOplockType
  1447. );
  1448. }
  1449. //
  1450. // The open was not mapped away from compatibility mode.
  1451. // Because the file is already open for normal sharing, this
  1452. // open request must be rejected.
  1453. //
  1454. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1455. KdPrint(( "DoCompatibilityOpen: Compatibility open of %wZ rejected; already open in normal mode\n",
  1456. RelativeName ));
  1457. }
  1458. status = STATUS_SHARING_VIOLATION;
  1459. goto sharing_violation;
  1460. } // if ( !Mfcb->CompatibilityOpen )
  1461. //
  1462. // The named file is open in compatibility mode. Get a pointer
  1463. // to the LFCB for the open. Determine whether the requesting
  1464. // session is the one that did the original open.
  1465. //
  1466. // Normally there will only be one LFCB linked to a
  1467. // compatibility mode MFCB. However, it is possible for there
  1468. // to briefly be multiple LFCBs. When an LFCB is in the process
  1469. // of closing, the ActiveRfcbCount will be 0, so a new open will
  1470. // be treated as the first open of the MFCB, and there will be
  1471. // two LFCBs linked to the MFCB. There can actually be more
  1472. // than two LFCBs linked if the rundown of the closing LFCBs
  1473. // takes some time. So the find "the" LFCB for the open, we go
  1474. // to the tail of the MFCB's list.
  1475. //
  1476. lfcb = CONTAINING_RECORD( Mfcb->LfcbList.Blink, LFCB, MfcbListEntry );
  1477. if ( lfcb->Session != WorkContext->Session ) {
  1478. //
  1479. // A different session has the file open in compatibility
  1480. // mode. Reject this open request.
  1481. //
  1482. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1483. KdPrint(( "DoCompatibilityOpen: Compatibility open of %wZ rejected; already open in compatibility mode\n",
  1484. RelativeName ));
  1485. }
  1486. status = STATUS_SHARING_VIOLATION;
  1487. goto sharing_violation;
  1488. }
  1489. //
  1490. // If this request is asking for more access than could be
  1491. // obtained when the file was originally opened, reject this
  1492. // open.
  1493. //
  1494. if ( !NT_SUCCESS(IoCheckDesiredAccess(
  1495. &desiredAccess,
  1496. lfcb->GrantedAccess )) ) {
  1497. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1498. KdPrint(( "DoCompatibilityOpen: Duplicate compatibility open of %wZ rejected; access denied\n", RelativeName ));
  1499. }
  1500. return STATUS_ACCESS_DENIED;
  1501. }
  1502. //
  1503. // The client has access. Allocate a new RFCB and link it into
  1504. // the existing LFCB. If any errors occur, CompleteOpen does
  1505. // full cleanup.
  1506. //
  1507. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1508. KdPrint(( "DoCompatibilityOpen: Duplicate compatibility open of %wZ accepted", RelativeName ));
  1509. }
  1510. IoStatusBlock->Information = FILE_OPENED;
  1511. status = CompleteOpen(
  1512. Rfcb,
  1513. Mfcb,
  1514. WorkContext,
  1515. lfcb,
  1516. NULL,
  1517. &desiredAccess,
  1518. 0, // ShareAccess
  1519. createOptions,
  1520. TRUE,
  1521. FALSE,
  1522. LfcbAddedToMfcbList
  1523. );
  1524. if( NT_SUCCESS( status ) &&
  1525. ( createDisposition == FILE_OVERWRITE ||
  1526. createDisposition == FILE_OVERWRITE_IF)
  1527. ) {
  1528. //
  1529. // The file was successfully opened, and the client wants it
  1530. // truncated. We need to do it here by hand since we
  1531. // didn't actually call the filesystem to open the file and it
  1532. // therefore never had a chance to truncate the file if the
  1533. // open modes requested it.
  1534. //
  1535. LARGE_INTEGER zero;
  1536. IO_STATUS_BLOCK ioStatusBlock;
  1537. zero.QuadPart = 0;
  1538. NtSetInformationFile( lfcb->FileHandle,
  1539. &ioStatusBlock,
  1540. &zero,
  1541. sizeof( zero ),
  1542. FileEndOfFileInformation
  1543. );
  1544. }
  1545. return status;
  1546. } // if ( mfcb->ActiveRfcbCount > 0 )
  1547. //
  1548. // The file is not already open (by the server, at least).
  1549. // Determine whether this should be mapped from a compatibility mode
  1550. // open to a normal sharing mode open.
  1551. //
  1552. smbOpenMode = SmbDesiredAccess;
  1553. if ( MapCompatibilityOpen( RelativeName, &smbOpenMode ) ) {
  1554. //
  1555. // The open has been mapped to a normal sharing mode.
  1556. //
  1557. return DoNormalOpen(
  1558. Rfcb,
  1559. Mfcb,
  1560. WorkContext,
  1561. IoStatusBlock,
  1562. smbOpenMode,
  1563. SmbFileAttributes,
  1564. SmbOpenFunction,
  1565. SmbAllocationSize,
  1566. RelativeName,
  1567. EaBuffer,
  1568. EaLength,
  1569. EaErrorOffset,
  1570. LfcbAddedToMfcbList,
  1571. RequestedOplockType
  1572. );
  1573. }
  1574. //
  1575. // The open was not mapped away from compatibility mode. Attempt to
  1576. // open the file for exclusive access.
  1577. //
  1578. // *** We try to open the file for the most access we'll ever need.
  1579. // This is because we fold multiple compatibility opens by the
  1580. // same client into a single local open. The client may open
  1581. // the file first for readonly access, then for read/write
  1582. // access. Because the local open is exclusive, we can't open
  1583. // again on the second remote open. We try to get Delete
  1584. // access, in case the client tries to delete the file while
  1585. // it's open.
  1586. //
  1587. //
  1588. // Set block size according to the AllocationSize in the request SMB.
  1589. //
  1590. allocationSize.QuadPart = SmbAllocationSize;
  1591. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1592. KdPrint(( "DoCompatibilityOpen: Opening file %wZ\n", RelativeName ));
  1593. }
  1594. //
  1595. // Get the value for fileAttributes.
  1596. //
  1597. SRV_SMB_ATTRIBUTES_TO_NT(
  1598. SmbFileAttributes,
  1599. &directory,
  1600. &fileAttributes
  1601. );
  1602. //
  1603. // Try to open the file for Read/Write/Delete access.
  1604. //
  1605. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1606. //
  1607. // Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
  1608. // component, the Io subsystem does not check it for us.
  1609. //
  1610. if( ARGUMENT_PRESENT( EaBuffer ) ) {
  1611. status = IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION)EaBuffer, EaLength, EaErrorOffset );
  1612. } else {
  1613. status = STATUS_SUCCESS;
  1614. }
  1615. if( NT_SUCCESS( status ) ) {
  1616. createOptions |= FILE_COMPLETE_IF_OPLOCKED;
  1617. status = SrvIoCreateFile(
  1618. WorkContext,
  1619. &fileHandle,
  1620. GENERIC_READ | GENERIC_WRITE | DELETE, // DesiredAccess
  1621. &objectAttributes,
  1622. IoStatusBlock,
  1623. &allocationSize,
  1624. fileAttributes,
  1625. 0L, // ShareAccess
  1626. createDisposition,
  1627. createOptions,
  1628. EaBuffer,
  1629. EaLength,
  1630. CreateFileTypeNone,
  1631. NULL, // ExtraCreateParameters
  1632. IO_FORCE_ACCESS_CHECK,
  1633. WorkContext->TreeConnect->Share
  1634. );
  1635. }
  1636. if ( status == STATUS_ACCESS_DENIED ) {
  1637. //
  1638. // The client doesn't have Read/Write/Delete access to the file.
  1639. // Try for Read/Write access.
  1640. //
  1641. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1642. KdPrint(( "DoCompatibilityOpen: r/w/d access denied.\n" ));
  1643. }
  1644. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1645. status = SrvIoCreateFile(
  1646. WorkContext,
  1647. &fileHandle,
  1648. GENERIC_READ | GENERIC_WRITE, // DesiredAccess
  1649. &objectAttributes,
  1650. IoStatusBlock,
  1651. &allocationSize,
  1652. fileAttributes,
  1653. 0L, // ShareAccess
  1654. createDisposition,
  1655. createOptions,
  1656. EaBuffer,
  1657. EaLength,
  1658. CreateFileTypeNone,
  1659. NULL, // ExtraPipeCreateParameters
  1660. IO_FORCE_ACCESS_CHECK,
  1661. WorkContext->TreeConnect->Share
  1662. );
  1663. if ( status == STATUS_ACCESS_DENIED ) {
  1664. //
  1665. // The client doesn't have Read/Write access to the file.
  1666. // Try Read or Write access, as appropriate.
  1667. //
  1668. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1669. KdPrint(( "DoCompatibilityOpen: r/w access denied.\n" ));
  1670. }
  1671. if ( (SmbDesiredAccess & SMB_DA_ACCESS_MASK) ==
  1672. SMB_DA_ACCESS_READ ) {
  1673. //
  1674. // !!! Should this be mapped to a normal sharing mode?
  1675. // Note that we already tried to map into normal
  1676. // mode once, but that failed. (With the current
  1677. // mapping algorithm, we can't get here unless soft
  1678. // compatibility is disabled.)
  1679. //
  1680. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1681. status = SrvIoCreateFile(
  1682. WorkContext,
  1683. &fileHandle,
  1684. GENERIC_READ, // DesiredAccess
  1685. &objectAttributes,
  1686. IoStatusBlock,
  1687. &allocationSize,
  1688. fileAttributes,
  1689. 0L, // ShareAccess
  1690. createDisposition,
  1691. createOptions,
  1692. EaBuffer,
  1693. EaLength,
  1694. CreateFileTypeNone,
  1695. NULL, // ExtraCreateParameters
  1696. IO_FORCE_ACCESS_CHECK,
  1697. WorkContext->TreeConnect->Share
  1698. );
  1699. } else if ( (SmbDesiredAccess & SMB_DA_ACCESS_MASK) ==
  1700. SMB_DA_ACCESS_WRITE ) {
  1701. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1702. status = SrvIoCreateFile(
  1703. WorkContext,
  1704. &fileHandle,
  1705. GENERIC_WRITE, // DesiredAccess
  1706. &objectAttributes,
  1707. IoStatusBlock,
  1708. &allocationSize,
  1709. fileAttributes,
  1710. 0L, // ShareAccess
  1711. createDisposition,
  1712. createOptions,
  1713. EaBuffer,
  1714. EaLength,
  1715. CreateFileTypeNone,
  1716. NULL, // NamedPipeCreateParameters
  1717. IO_FORCE_ACCESS_CHECK,
  1718. WorkContext->TreeConnect->Share
  1719. );
  1720. }
  1721. //
  1722. // If the user didn't have this permission, update the
  1723. // statistics database.
  1724. //
  1725. if ( status == STATUS_ACCESS_DENIED ) {
  1726. SrvStatistics.AccessPermissionErrors++;
  1727. }
  1728. }
  1729. }
  1730. //
  1731. // If we got sharing violation, just get a handle so that we can wait
  1732. // for an oplock break.
  1733. //
  1734. sharing_violation:
  1735. //
  1736. // If we got sharing violation and this is a disk file, and this is
  1737. // the first open attempt, setup for a blocking open attempt. If the
  1738. // file is batch oplocked, the non-blocking open would fail, and the
  1739. // oplock will not break.
  1740. //
  1741. if ( status == STATUS_SHARING_VIOLATION &&
  1742. WorkContext->ProcessingCount == 1 &&
  1743. WorkContext->TreeConnect->Share->ShareType == ShareTypeDisk ) {
  1744. WorkContext->Parameters2.Open.TemporaryOpen = TRUE;
  1745. }
  1746. if ( !NT_SUCCESS(status) ) {
  1747. //
  1748. // All of the open attempts failed.
  1749. //
  1750. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1751. KdPrint(( "DoCompatibilityOpen: all opens failed; status = %X\n",
  1752. status ));
  1753. }
  1754. //
  1755. // Set the error offset if needed.
  1756. //
  1757. if ( ARGUMENT_PRESENT(EaErrorOffset) &&
  1758. status == STATUS_INVALID_EA_NAME ) {
  1759. *EaErrorOffset = (ULONG)IoStatusBlock->Information;
  1760. IoStatusBlock->Information = 0;
  1761. }
  1762. return status;
  1763. }
  1764. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 11, 0 );
  1765. //
  1766. // The file has been successfully opened for exclusive access, with
  1767. // at least as much desired access as requested by the client.
  1768. // Attempt to allocate structures to represent the open. If any
  1769. // errors occur, CompleteOpen does full cleanup, including closing
  1770. // the file.
  1771. //
  1772. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1773. KdPrint(( "DoCompatibilityOpen: Open of %wZ succeeded, file handle: 0x%p\n", RelativeName, fileHandle ));
  1774. }
  1775. completionStatus = CompleteOpen(
  1776. Rfcb,
  1777. Mfcb,
  1778. WorkContext,
  1779. NULL,
  1780. fileHandle,
  1781. &desiredAccess,
  1782. 0, // ShareAccess
  1783. createOptions,
  1784. TRUE,
  1785. FALSE,
  1786. LfcbAddedToMfcbList
  1787. );
  1788. //
  1789. // Return the "interesting" status code. If CompleteOpen() succeeds
  1790. // return the open status. If it fails, it will clean up the open
  1791. // file, and we return a failure status.
  1792. //
  1793. if ( !NT_SUCCESS( completionStatus ) ) {
  1794. return completionStatus;
  1795. } else {
  1796. return status;
  1797. }
  1798. } // DoCompatibilityOpen
  1799. NTSTATUS
  1800. DoFcbOpen(
  1801. OUT PRFCB *Rfcb,
  1802. IN PMFCB Mfcb,
  1803. IN OUT PWORK_CONTEXT WorkContext,
  1804. OUT PIO_STATUS_BLOCK IoStatusBlock,
  1805. IN USHORT SmbFileAttributes,
  1806. IN USHORT SmbOpenFunction,
  1807. IN ULONG SmbAllocationSize,
  1808. IN PUNICODE_STRING RelativeName,
  1809. IN PVOID EaBuffer OPTIONAL,
  1810. IN ULONG EaLength,
  1811. OUT PULONG EaErrorOffset OPTIONAL,
  1812. OUT PBOOLEAN LfcbAddedToMfcbList
  1813. )
  1814. /*++
  1815. Routine Description:
  1816. Processes an FCB open.
  1817. *** The MFCB lock must be held on entry to this routine; the lock
  1818. remains held on exit.
  1819. Arguments:
  1820. Rfcb - A pointer to a pointer to an RFCB that will point to the
  1821. newly-created RFCB.
  1822. Mfcb - A pointer to the MFCB for this file
  1823. WorkContext - Work context block for the operation.
  1824. IoStatusBlock - A pointer to an IO status block.
  1825. SmbFileAttributes - File attributes in SMB protocol format.
  1826. SmbOpenFunction - Open function in SMB protocol format.
  1827. SmbAllocationSize - Allocation size for new files.
  1828. RelativeName - The share-relative name of the file being opened.
  1829. EaBuffer - Optional pointer to a full EA list to pass to SrvIoCreateFile.
  1830. EaLength - Length of the EA buffer.
  1831. EaErrorOffset - Optional pointer to the location in which to write
  1832. the offset to the EA that caused an error.
  1833. LfcbAddedToMfcbList - Pointer to a boolean that will be set to TRUE if
  1834. an lfcb is added to the mfcb list of lfcbs.
  1835. Return Value:
  1836. NTSTATUS - Indicates what occurred.
  1837. --*/
  1838. {
  1839. NTSTATUS status;
  1840. NTSTATUS completionStatus;
  1841. PLIST_ENTRY lfcbEntry;
  1842. PLIST_ENTRY rfcbEntry;
  1843. PRFCB rfcb;
  1844. PPAGED_RFCB pagedRfcb;
  1845. PLFCB lfcb;
  1846. HANDLE fileHandle;
  1847. OBJECT_ATTRIBUTES objectAttributes;
  1848. ULONG attributes;
  1849. LARGE_INTEGER allocationSize;
  1850. ULONG fileAttributes;
  1851. BOOLEAN directory;
  1852. ULONG createOptions;
  1853. ULONG createDisposition;
  1854. ULONG shareAccess;
  1855. BOOLEAN compatibilityOpen;
  1856. PAGED_CODE( );
  1857. *LfcbAddedToMfcbList = FALSE;
  1858. //
  1859. // Set createDisposition parameter from OpenFunction.
  1860. //
  1861. status = MapOpenFunction( SmbOpenFunction, &createDisposition );
  1862. if ( !NT_SUCCESS(status) ) {
  1863. return status;
  1864. }
  1865. //
  1866. // Set createOptions parameter.
  1867. //
  1868. if ( (SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 ) &
  1869. SMB_FLAGS2_KNOWS_EAS) == 0) {
  1870. //
  1871. // This guy does not know eas
  1872. //
  1873. createOptions = FILE_NON_DIRECTORY_FILE |
  1874. FILE_NO_EA_KNOWLEDGE;
  1875. } else {
  1876. createOptions = FILE_NON_DIRECTORY_FILE;
  1877. }
  1878. //
  1879. // We're going to open this file relative to the root directory
  1880. // of the share. Load up the necessary fields in the object
  1881. // attributes structure.
  1882. //
  1883. if ( WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ) {
  1884. attributes = OBJ_CASE_INSENSITIVE;
  1885. } else if ( WorkContext->Session->UsingUppercasePaths ) {
  1886. attributes = OBJ_CASE_INSENSITIVE;
  1887. } else {
  1888. attributes = 0L;
  1889. }
  1890. SrvInitializeObjectAttributes_U(
  1891. &objectAttributes,
  1892. RelativeName,
  1893. attributes,
  1894. NULL,
  1895. NULL
  1896. );
  1897. createOptions |= FILE_COMPLETE_IF_OPLOCKED;
  1898. if ( Mfcb->ActiveRfcbCount > 0 ) {
  1899. //
  1900. // The named file is already open by the server. If the client
  1901. // specified that it didn't want to open an existing file,
  1902. // reject this open.
  1903. //
  1904. if ( createDisposition == FILE_CREATE ) {
  1905. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1906. KdPrint(( "DoFcbOpen: FCB open of %wZ rejected; wants to create\n", RelativeName ));
  1907. }
  1908. return STATUS_OBJECT_NAME_COLLISION;
  1909. }
  1910. //
  1911. // If the requesting session already has the file open in FCB
  1912. // mode, fold this open into the existing open by returning a
  1913. // pointer to the existing RFCB.
  1914. //
  1915. // *** Multiple FCB opens are folded together because the client
  1916. // may send only one close; that single close closes all FCB
  1917. // opens by the client.
  1918. //
  1919. for ( lfcbEntry = Mfcb->LfcbList.Flink;
  1920. lfcbEntry != &Mfcb->LfcbList;
  1921. lfcbEntry = lfcbEntry->Flink ) {
  1922. lfcb = CONTAINING_RECORD( lfcbEntry, LFCB, MfcbListEntry );
  1923. if ( lfcb->Session == WorkContext->Session ) {
  1924. //
  1925. // This LFCB is owned by the requesting session. Check
  1926. // for RFCBs opened in FCB mode.
  1927. //
  1928. for ( rfcbEntry = lfcb->RfcbList.Flink;
  1929. rfcbEntry != &lfcb->RfcbList;
  1930. rfcbEntry = rfcbEntry->Flink ) {
  1931. pagedRfcb = CONTAINING_RECORD(
  1932. rfcbEntry,
  1933. PAGED_RFCB,
  1934. LfcbListEntry
  1935. );
  1936. rfcb = pagedRfcb->PagedHeader.NonPagedBlock;
  1937. if ( (pagedRfcb->FcbOpenCount != 0) &&
  1938. (GET_BLOCK_STATE(rfcb) == BlockStateActive) ) {
  1939. //
  1940. // The requesting session already has the file
  1941. // open in FCB mode. Rather than reopening the
  1942. // file, or even linking a new RFCB off the
  1943. // LFCB, we just return a pointer to the
  1944. // existing RFCB.
  1945. //
  1946. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1947. KdPrint(( "DoFcbOpen: FCB open of %wZ accepted; duplicates FCB open\n", RelativeName ));
  1948. }
  1949. SrvReferenceRfcb( rfcb );
  1950. pagedRfcb->FcbOpenCount++;
  1951. IoStatusBlock->Information = FILE_OPENED;
  1952. WorkContext->Rfcb = rfcb;
  1953. *Rfcb = rfcb;
  1954. return STATUS_SUCCESS;
  1955. } // if ( rfcb->FcbOpenCount != 0 )
  1956. } // for ( rfcbEntry = lfcb->RfcbList.Flink; ...
  1957. } // if ( lfcb->Session == WorkContext->Session )
  1958. } // for ( lfcbEntry = mfcb->LfcbList.Flink; ...
  1959. //
  1960. // The server has the file open, but the requesting session
  1961. // doesn't already have an FCB open for the file. If the
  1962. // existing open is a compatibility mode open open by this
  1963. // session, we just add a new RFCB. If it's a compatibility
  1964. // mode open by a different session, we reject this open.
  1965. //
  1966. if ( Mfcb->CompatibilityOpen ) {
  1967. //
  1968. // The named file is open in compatibility mode. Get a
  1969. // pointer to the LFCB for the open. Determine whether the
  1970. // requesting session is the one that did the original open.
  1971. //
  1972. // Normally there will only be one LFCB linked to a
  1973. // compatibility mode MFCB. However, it is possible for
  1974. // there to briefly be multiple LFCBs. When an LFCB is in
  1975. // the process of closing, the ActiveRfcbCount will be 0, so
  1976. // a new open will be treated as the first open of the MFCB,
  1977. // and there will be two LFCBs linked to the MFCB. There
  1978. // can actually be more than two LFCBs linked if the rundown
  1979. // of the closing LFCBs takes some time. So the find "the"
  1980. // LFCB for the open, we go to the tail of the MFCB's list.
  1981. //
  1982. lfcb = CONTAINING_RECORD( Mfcb->LfcbList.Blink, LFCB, MfcbListEntry );
  1983. if ( lfcb->Session != WorkContext->Session ) {
  1984. //
  1985. // A different session has the file open in
  1986. // compatibility mode. Reject this open request.
  1987. //
  1988. IF_SMB_DEBUG(OPEN_CLOSE2) {
  1989. KdPrint(( "DoFcbOpen: FCB open of %wZ rejected; already open in compatibility mode\n",
  1990. RelativeName ));
  1991. }
  1992. return STATUS_SHARING_VIOLATION;
  1993. }
  1994. //
  1995. // The same client has the file open in compatibility mode.
  1996. // Allocate a new RFCB and link it into the existing LFCB.
  1997. // If any errors occur, CompleteOpen does full cleanup.
  1998. //
  1999. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2000. KdPrint(( "DoFcbOpen: FCB open of %wZ accepted; duplicates compatibility open\n", RelativeName ));
  2001. }
  2002. IoStatusBlock->Information = FILE_OPENED;
  2003. status = CompleteOpen(
  2004. Rfcb,
  2005. Mfcb,
  2006. WorkContext,
  2007. lfcb,
  2008. NULL,
  2009. NULL,
  2010. 0, // ShareAccess
  2011. 0,
  2012. TRUE,
  2013. TRUE,
  2014. LfcbAddedToMfcbList
  2015. );
  2016. return status;
  2017. } // if ( mfcb->CompatibilityOpen )
  2018. } // if ( mfcb->ActiveRfcbCount > 0 )
  2019. //
  2020. // Either the file is not already open by the server, or it's open
  2021. // for normal sharing, and not in FCB mode by this session. Because
  2022. // we're supposed to give the client maximum access to the file, we
  2023. // do the following:
  2024. //
  2025. // 1) Try to open the file for read/write/delete, exclusive access.
  2026. // Obviously this will fail if the file is already open. But
  2027. // what we're really trying to find out is what access the client
  2028. // has to the file. If this attempt fails with a sharing
  2029. // violation, then we know the client has write/delete access,
  2030. // but someone else has it open. So we can't get compatibility
  2031. // mode. Therefore, we reject the open. On the other hand, if
  2032. // we get an access denied error, then we know the client can't
  2033. // write/delete the file, so we try again with write access. Of
  2034. // course, this first open could succeed, in which case the
  2035. // client has the file open for read/write in compatibility mode.
  2036. //
  2037. // 2) Try to open the file for read/write, exclusive access. As
  2038. // above, if it fails with a sharing violation, then we know the
  2039. // client has write access, but someone else has it open. So we
  2040. // can't get compatibility mode, and we reject the open. If we
  2041. // get an access denied error, then we know the client can't
  2042. // write the file, so we try again with readonly access. If this
  2043. // open succeeds, the client has the file open for read/write in
  2044. // compatibility mode.
  2045. //
  2046. // 3) If we get here, we know the client can't write to the file,
  2047. // so we try to open the file for readonly, shared access. This
  2048. // no longer a compatibility mode open. If we get any kind of a
  2049. // failure here, we're just out of luck.
  2050. //
  2051. compatibilityOpen = TRUE;
  2052. //
  2053. // Set block size according to the AllocationSize in the request SMB.
  2054. //
  2055. allocationSize.QuadPart = SmbAllocationSize;
  2056. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2057. KdPrint(( "DoFcbOpen: Opening file %wZ\n", RelativeName ));
  2058. }
  2059. //
  2060. // Get the value for fileAttributes.
  2061. //
  2062. SRV_SMB_ATTRIBUTES_TO_NT(
  2063. SmbFileAttributes,
  2064. &directory,
  2065. &fileAttributes
  2066. );
  2067. //
  2068. // Try to open the file for Read/Write/Delete access.
  2069. //
  2070. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  2071. //
  2072. // Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
  2073. // component, the Io subsystem does not check it for us.
  2074. //
  2075. if( ARGUMENT_PRESENT( EaBuffer ) ) {
  2076. status = IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION)EaBuffer, EaLength, EaErrorOffset );
  2077. } else {
  2078. status = STATUS_SUCCESS;
  2079. }
  2080. if( NT_SUCCESS( status ) ) {
  2081. status = SrvIoCreateFile(
  2082. WorkContext,
  2083. &fileHandle,
  2084. GENERIC_READ | GENERIC_WRITE | DELETE, // DesiredAccess
  2085. &objectAttributes,
  2086. IoStatusBlock,
  2087. &allocationSize,
  2088. fileAttributes,
  2089. 0L, // ShareAccess
  2090. createDisposition,
  2091. createOptions,
  2092. EaBuffer,
  2093. EaLength,
  2094. CreateFileTypeNone,
  2095. NULL, // ExtraCreateParameters
  2096. IO_FORCE_ACCESS_CHECK,
  2097. WorkContext->TreeConnect->Share
  2098. );
  2099. }
  2100. if ( status == STATUS_ACCESS_DENIED ) {
  2101. //
  2102. // The client doesn't have Read/Write/Delete access to the file.
  2103. // Try for Read/Write access.
  2104. //
  2105. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2106. KdPrint(( "DoFcbOpen: r/w/d access denied.\n" ));
  2107. }
  2108. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  2109. status = SrvIoCreateFile(
  2110. WorkContext,
  2111. &fileHandle,
  2112. GENERIC_READ | GENERIC_WRITE, // DesiredAccess
  2113. &objectAttributes,
  2114. IoStatusBlock,
  2115. &allocationSize,
  2116. fileAttributes,
  2117. 0L, // ShareAccess
  2118. createDisposition,
  2119. createOptions,
  2120. EaBuffer,
  2121. EaLength,
  2122. CreateFileTypeNone,
  2123. NULL, // ExtraCreateParameters
  2124. IO_FORCE_ACCESS_CHECK,
  2125. WorkContext->TreeConnect->Share
  2126. );
  2127. if ( status == STATUS_ACCESS_DENIED ) {
  2128. //
  2129. // The client doesn't have Read/Write access to the file.
  2130. // Try Read access. If soft compatibility mapping is
  2131. // enabled, use SHARE=READ and don't call this a
  2132. // compatibility mode open.
  2133. //
  2134. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2135. KdPrint(( "DoFcbOpen: r/w access denied.\n" ));
  2136. }
  2137. shareAccess = 0;
  2138. if ( SrvEnableSoftCompatibility ) {
  2139. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2140. KdPrint(( "DoFcbOpen: FCB open of %wZ mapped to normal open\n", RelativeName ));
  2141. }
  2142. shareAccess = FILE_SHARE_READ;
  2143. compatibilityOpen = FALSE;
  2144. }
  2145. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  2146. status = SrvIoCreateFile(
  2147. WorkContext,
  2148. &fileHandle,
  2149. GENERIC_READ, // DesiredAccess
  2150. &objectAttributes,
  2151. IoStatusBlock,
  2152. &allocationSize,
  2153. fileAttributes,
  2154. shareAccess,
  2155. createDisposition,
  2156. createOptions,
  2157. EaBuffer,
  2158. EaLength,
  2159. CreateFileTypeNone,
  2160. NULL, // ExtraCreateParameters
  2161. IO_FORCE_ACCESS_CHECK,
  2162. WorkContext->TreeConnect->Share
  2163. );
  2164. //
  2165. // If the user didn't have this permission, update the
  2166. // statistics database.
  2167. //
  2168. if ( status == STATUS_ACCESS_DENIED ) {
  2169. SrvStatistics.AccessPermissionErrors++;
  2170. }
  2171. }
  2172. }
  2173. //
  2174. // If we got sharing violation and this is a disk file, and this is
  2175. // the first open attempt, setup for a blocking open attempt. If the
  2176. // file is batch oplocked, the non-blocking open would fail, and the
  2177. // oplock will not break.
  2178. //
  2179. if ( status == STATUS_SHARING_VIOLATION &&
  2180. WorkContext->ProcessingCount == 1 &&
  2181. WorkContext->TreeConnect->Share->ShareType == ShareTypeDisk ) {
  2182. WorkContext->Parameters2.Open.TemporaryOpen = TRUE;
  2183. }
  2184. if ( !NT_SUCCESS(status) ) {
  2185. //
  2186. // All of the open attempts failed.
  2187. //
  2188. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2189. KdPrint(( "DoFcbOpen: all opens failed; status = %X\n",
  2190. status ));
  2191. }
  2192. //
  2193. // Set the error offset if needed.
  2194. //
  2195. if ( ARGUMENT_PRESENT(EaErrorOffset) ) {
  2196. *EaErrorOffset = (ULONG)IoStatusBlock->Information;
  2197. }
  2198. return status;
  2199. }
  2200. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 12, 0 );
  2201. //
  2202. // The file has been successfully opened. Attempt to allocate
  2203. // structures to represent the open. If any errors occur,
  2204. // CompleteOpen does full cleanup, including closing the file.
  2205. //
  2206. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2207. KdPrint(( "DoFcbOpen: Open of %wZ succeeded, file handle: 0x%p\n", RelativeName, fileHandle ));
  2208. }
  2209. completionStatus = CompleteOpen(
  2210. Rfcb,
  2211. Mfcb,
  2212. WorkContext,
  2213. NULL,
  2214. fileHandle,
  2215. NULL,
  2216. 0, // ShareAccess
  2217. 0,
  2218. compatibilityOpen,
  2219. TRUE,
  2220. LfcbAddedToMfcbList
  2221. );
  2222. //
  2223. // Return the "interesting" status code. If CompleteOpen() succeeds
  2224. // return the open status. If it fails, it will clean up the open
  2225. // file, and we return a failure status.
  2226. //
  2227. if ( !NT_SUCCESS( completionStatus ) ) {
  2228. return completionStatus;
  2229. } else {
  2230. return status;
  2231. }
  2232. } // DoFcbOpen
  2233. PTABLE_ENTRY
  2234. FindAndClaimFileTableEntry (
  2235. IN PCONNECTION Connection,
  2236. OUT PSHORT FidIndex
  2237. )
  2238. {
  2239. PTABLE_HEADER tableHeader;
  2240. SHORT fidIndex;
  2241. PTABLE_ENTRY entry;
  2242. KIRQL oldIrql;
  2243. UNLOCKABLE_CODE( 8FIL );
  2244. tableHeader = &Connection->FileTable;
  2245. ACQUIRE_SPIN_LOCK( &Connection->SpinLock, &oldIrql );
  2246. if ( tableHeader->FirstFreeEntry == -1
  2247. &&
  2248. SrvGrowTable(
  2249. tableHeader,
  2250. SrvInitialFileTableSize,
  2251. SrvMaxFileTableSize,
  2252. NULL ) == FALSE
  2253. ) {
  2254. RELEASE_SPIN_LOCK( &Connection->SpinLock, oldIrql );
  2255. return NULL;
  2256. }
  2257. //
  2258. // Remove the FID slot from the free list, but don't set its owner
  2259. // and sequence number yet.
  2260. //
  2261. fidIndex = tableHeader->FirstFreeEntry;
  2262. entry = &tableHeader->Table[fidIndex];
  2263. tableHeader->FirstFreeEntry = entry->NextFreeEntry;
  2264. DEBUG entry->NextFreeEntry = -2;
  2265. if ( tableHeader->LastFreeEntry == fidIndex ) {
  2266. tableHeader->LastFreeEntry = -1;
  2267. }
  2268. RELEASE_SPIN_LOCK( &Connection->SpinLock, oldIrql );
  2269. *FidIndex = fidIndex;
  2270. return entry;
  2271. } // FindAndClaimFileTableEntry
  2272. NTSTATUS
  2273. CompleteOpen (
  2274. OUT PRFCB *Rfcb,
  2275. IN PMFCB Mfcb,
  2276. IN OUT PWORK_CONTEXT WorkContext,
  2277. IN PLFCB ExistingLfcb OPTIONAL,
  2278. IN HANDLE FileHandle OPTIONAL,
  2279. IN PACCESS_MASK RemoteGrantedAccess OPTIONAL,
  2280. IN ULONG ShareAccess,
  2281. IN ULONG FileMode,
  2282. IN BOOLEAN CompatibilityOpen,
  2283. IN BOOLEAN FcbOpen,
  2284. OUT PBOOLEAN LfcbAddedToMfcbList
  2285. )
  2286. /*++
  2287. Routine Description:
  2288. Completes structure allocation, initialization, and linking after
  2289. a successful open. Updates Master File Table as appropriate.
  2290. Adds entry to connection's file table.
  2291. *** The MFCB lock must be held on entry to this routine; the lock
  2292. remains held on exit.
  2293. Arguments:
  2294. Rfcb - A pointer to a pointer to an RFCB that will point to the
  2295. newly-created RFCB.
  2296. Mfcb - A pointer to the MFCB for this file.
  2297. WorkContext - Work context block for the operation.
  2298. ExistingLfcb - Optional address of an existing Local File Control
  2299. Block. Specified when folding a duplicate compatibility mode
  2300. open into a single local open.
  2301. FileHandle - Optional file handle obtained from SrvIoCreateFile.
  2302. Ignored when ExistingLfcb is specified.
  2303. RemoteGrantedAccess - Optional granted access to be stored in new
  2304. RFCB. If not specified, granted access from LFCB (i.e., access
  2305. obtained on local open) is used.
  2306. FileMode - Same value specified as CreateOptions on SrvIoCreateFile
  2307. call. Indicates whether client wants writethrough mode.
  2308. CompatibilityOpen - TRUE if this is a compatibility mode open.
  2309. FcbOpen - TRUE if this is an FCB open.
  2310. LfcbAddedToMfcbList - Pointer to a boolean that will be set to TRUE if
  2311. an lfcb is added to the mfcb list of lfcbs.
  2312. Return Value:
  2313. NTSTATUS - Indicates what occurred.
  2314. --*/
  2315. {
  2316. NTSTATUS status;
  2317. PRFCB rfcb;
  2318. PPAGED_RFCB pagedRfcb;
  2319. PLFCB newLfcb;
  2320. PLFCB lfcb;
  2321. BOOLEAN rfcbLinkedToLfcb;
  2322. PFILE_OBJECT fileObject;
  2323. OBJECT_HANDLE_INFORMATION handleInformation;
  2324. PCONNECTION connection;
  2325. PTABLE_ENTRY entry;
  2326. SHORT fidIndex;
  2327. ULONG pid;
  2328. PAGED_CODE( );
  2329. //
  2330. // Initialize various fields for the error handler.
  2331. //
  2332. rfcb = NULL;
  2333. newLfcb = NULL;
  2334. rfcbLinkedToLfcb = FALSE;
  2335. fileObject = NULL;
  2336. *LfcbAddedToMfcbList = FALSE;
  2337. //
  2338. // Allocate an RFCB.
  2339. //
  2340. SrvAllocateRfcb( &rfcb, WorkContext );
  2341. if ( rfcb == NULL ) {
  2342. ULONG length = sizeof( RFCB );
  2343. //
  2344. // Unable to allocate RFCB. Return an error to the client.
  2345. //
  2346. IF_DEBUG(ERRORS) {
  2347. KdPrint(( "CompleteOpen: Unable to allocate RFCB\n" ));
  2348. }
  2349. status = STATUS_INSUFF_SERVER_RESOURCES;
  2350. goto error_exit;
  2351. }
  2352. pagedRfcb = rfcb->PagedRfcb;
  2353. //
  2354. // If no existing LFCB address was passed in (i.e., if this is not a
  2355. // duplicate compatibility mode open), allocate and initialize a new
  2356. // LFCB.
  2357. //
  2358. if ( ARGUMENT_PRESENT( ExistingLfcb ) ) {
  2359. ASSERT( CompatibilityOpen );
  2360. ASSERT( ExistingLfcb->CompatibilityOpen );
  2361. lfcb = ExistingLfcb;
  2362. } else {
  2363. PFAST_IO_DISPATCH fastIoDispatch;
  2364. SrvAllocateLfcb( &newLfcb, WorkContext );
  2365. if ( newLfcb == NULL ) {
  2366. //
  2367. // Unable to allocate LFCB. Return an error to the client.
  2368. //
  2369. IF_DEBUG(ERRORS) {
  2370. KdPrint(( "CompleteOpen: Unable to allocate LFCB\n" ));
  2371. }
  2372. status = STATUS_INSUFF_SERVER_RESOURCES;
  2373. goto error_exit;
  2374. }
  2375. lfcb = newLfcb;
  2376. //
  2377. // Get a pointer to the file object, so that we can directly
  2378. // build IRPs for asynchronous operations (read and write).
  2379. // Also, get the granted access mask, so that we can prevent the
  2380. // client from doing things that it isn't allowed to do.
  2381. //
  2382. // *** Note that the granted access on the local open may allow
  2383. // more access than was requested on the remote open.
  2384. // That's why the RFCB has its own granted access field.
  2385. //
  2386. status = ObReferenceObjectByHandle(
  2387. FileHandle,
  2388. 0,
  2389. NULL,
  2390. KernelMode,
  2391. (PVOID *)&fileObject,
  2392. &handleInformation
  2393. );
  2394. if ( !NT_SUCCESS(status) ) {
  2395. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  2396. //
  2397. // This internal error bugchecks the system.
  2398. //
  2399. INTERNAL_ERROR(
  2400. ERROR_LEVEL_IMPOSSIBLE,
  2401. "CompleteOpen: unable to reference file handle 0x%lx",
  2402. FileHandle,
  2403. NULL
  2404. );
  2405. goto error_exit;
  2406. }
  2407. //
  2408. // Initialize the new LFCB.
  2409. //
  2410. lfcb->FileHandle = FileHandle;
  2411. lfcb->FileObject = fileObject;
  2412. lfcb->GrantedAccess = handleInformation.GrantedAccess;
  2413. lfcb->DeviceObject = IoGetRelatedDeviceObject( fileObject );
  2414. fastIoDispatch = lfcb->DeviceObject->DriverObject->FastIoDispatch;
  2415. if ( fastIoDispatch != NULL ) {
  2416. lfcb->FastIoRead = fastIoDispatch->FastIoRead;
  2417. lfcb->FastIoWrite = fastIoDispatch->FastIoWrite;
  2418. lfcb->FastIoLock = fastIoDispatch->FastIoLock;
  2419. lfcb->FastIoUnlockSingle = fastIoDispatch->FastIoUnlockSingle;
  2420. //
  2421. // Fill in Mdl calls. If the file system's vector is large enough,
  2422. // we still need to check if one of the routines is specified. But
  2423. // if one is specified they all must be.
  2424. //
  2425. if ((fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) &&
  2426. (fastIoDispatch->MdlRead != NULL)) {
  2427. lfcb->MdlRead = fastIoDispatch->MdlRead;
  2428. lfcb->MdlReadComplete = fastIoDispatch->MdlReadComplete;
  2429. lfcb->PrepareMdlWrite = fastIoDispatch->PrepareMdlWrite;
  2430. lfcb->MdlWriteComplete = fastIoDispatch->MdlWriteComplete;
  2431. } else if( IoGetBaseFileSystemDeviceObject( fileObject ) == lfcb->DeviceObject ) {
  2432. //
  2433. // Otherwise default to the original FsRtl routines if we are right atop
  2434. // a filesystem.
  2435. //
  2436. lfcb->MdlRead = FsRtlMdlReadDev;
  2437. lfcb->MdlReadComplete = FsRtlMdlReadCompleteDev;
  2438. lfcb->PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
  2439. lfcb->MdlWriteComplete = FsRtlMdlWriteCompleteDev;
  2440. } else {
  2441. //
  2442. // Otherwise, make them fail!
  2443. //
  2444. lfcb->MdlRead = SrvFailMdlReadDev;
  2445. lfcb->PrepareMdlWrite = SrvFailPrepareMdlWriteDev;
  2446. }
  2447. //
  2448. // Fill in Mdl calls, if the file system vector is long enough.
  2449. // For now we will just copy all six compressed routines over,
  2450. // whether they are actually supplied or not (NULL). There are
  2451. // no default routines for these, they are either supported or not.
  2452. //
  2453. if ((fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteCompleteCompressed))) {
  2454. lfcb->FastIoReadCompressed = fastIoDispatch->FastIoReadCompressed;
  2455. lfcb->FastIoWriteCompressed = fastIoDispatch->FastIoWriteCompressed;
  2456. lfcb->MdlReadCompleteCompressed = fastIoDispatch->MdlReadCompleteCompressed;
  2457. lfcb->MdlWriteCompleteCompressed = fastIoDispatch->MdlWriteCompleteCompressed;
  2458. }
  2459. }
  2460. lfcb->FileMode = FileMode & ~FILE_COMPLETE_IF_OPLOCKED;
  2461. lfcb->CompatibilityOpen = CompatibilityOpen;
  2462. }
  2463. //
  2464. // Initialize the RFCB.
  2465. //
  2466. if ( ARGUMENT_PRESENT( RemoteGrantedAccess ) ) {
  2467. rfcb->GrantedAccess = *RemoteGrantedAccess;
  2468. IoCheckDesiredAccess( &rfcb->GrantedAccess, lfcb->GrantedAccess );
  2469. } else {
  2470. rfcb->GrantedAccess = lfcb->GrantedAccess;
  2471. }
  2472. rfcb->ShareAccess = ShareAccess;
  2473. rfcb->FileMode = lfcb->FileMode;
  2474. rfcb->Mfcb = Mfcb;
  2475. #ifdef SRVCATCH
  2476. rfcb->SrvCatch = Mfcb->SrvCatch;
  2477. #endif
  2478. //
  2479. // If delete on close was specified, don't attempt to cache this rfcb.
  2480. //
  2481. if ( (FileMode & FILE_DELETE_ON_CLOSE) != 0 ) {
  2482. rfcb->IsCacheable = FALSE;
  2483. }
  2484. //
  2485. // Check for granted access
  2486. //
  2487. //
  2488. // Locks
  2489. //
  2490. CHECK_FUNCTION_ACCESS(
  2491. rfcb->GrantedAccess,
  2492. IRP_MJ_LOCK_CONTROL,
  2493. IRP_MN_LOCK,
  2494. 0,
  2495. &status
  2496. );
  2497. if ( NT_SUCCESS(status) ) {
  2498. rfcb->LockAccessGranted = TRUE;
  2499. } else {
  2500. IF_DEBUG(ERRORS) {
  2501. KdPrint(( "CompleteOpen: Lock IoCheckFunctionAccess failed: "
  2502. "0x%X, GrantedAccess: %lx\n",
  2503. status, rfcb->GrantedAccess ));
  2504. }
  2505. }
  2506. //
  2507. // Unlocks
  2508. //
  2509. CHECK_FUNCTION_ACCESS(
  2510. rfcb->GrantedAccess,
  2511. IRP_MJ_LOCK_CONTROL,
  2512. IRP_MN_UNLOCK_SINGLE,
  2513. 0,
  2514. &status
  2515. );
  2516. if ( NT_SUCCESS(status) ) {
  2517. rfcb->UnlockAccessGranted = TRUE;
  2518. } else {
  2519. IF_DEBUG(ERRORS) {
  2520. KdPrint(( "CompleteOpen: Unlock IoCheckFunctionAccess failed: "
  2521. "0x%X, GrantedAccess: %lx\n",
  2522. status, rfcb->GrantedAccess ));
  2523. }
  2524. }
  2525. //
  2526. // Reads
  2527. //
  2528. CHECK_FUNCTION_ACCESS(
  2529. rfcb->GrantedAccess,
  2530. IRP_MJ_READ,
  2531. 0, 0, &status );
  2532. if ( NT_SUCCESS(status) ) {
  2533. rfcb->ReadAccessGranted = TRUE;
  2534. } else {
  2535. IF_DEBUG(ERRORS) {
  2536. KdPrint(( "CompleteOpen: Read IoCheckFunctionAccess failed: "
  2537. "0x%X, GrantedAccess: %lx\n",
  2538. status, rfcb->GrantedAccess ));
  2539. }
  2540. }
  2541. //
  2542. // Writes
  2543. //
  2544. if( rfcb->GrantedAccess & FILE_WRITE_DATA ) {
  2545. rfcb->WriteAccessGranted = TRUE;
  2546. }
  2547. if( rfcb->GrantedAccess & FILE_APPEND_DATA ) {
  2548. rfcb->AppendAccessGranted = TRUE;
  2549. //
  2550. // This hack is required for now. The problem is that clients, given an
  2551. // oplock, will write whole pages to the server. The offset of the page
  2552. // will likely cover the last part of the file, and the server will reject
  2553. // the write. Code needs to be added to the server to ignore the
  2554. // first part of the page. Or we could just not give the client an oplock
  2555. // if append access is granted. For now, we revert to prior NT4 behavior.
  2556. //
  2557. rfcb->WriteAccessGranted = TRUE;
  2558. }
  2559. //
  2560. // Copy the TID from the tree connect into the RFCB. We do this to
  2561. // reduce the number of indirections we have to take. Save the PID
  2562. // of the remote process that's opening the file. We'll need this
  2563. // if we get a Process Exit SMB.
  2564. //
  2565. rfcb->Tid = WorkContext->TreeConnect->Tid;
  2566. rfcb->Pid = SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2567. pid = rfcb->Pid;
  2568. rfcb->Uid = WorkContext->Session->Uid;
  2569. if ( FcbOpen ) {
  2570. pagedRfcb->FcbOpenCount = 1;
  2571. }
  2572. if ( WorkContext->Endpoint->IsConnectionless ) {
  2573. rfcb->WriteMpx.FileObject = lfcb->FileObject;
  2574. rfcb->WriteMpx.MpxGlommingAllowed =
  2575. (BOOLEAN)((lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) != 0);
  2576. }
  2577. //
  2578. // If this is a named pipe, fill in the named pipe specific
  2579. // information. The default mode on open is always byte mode,
  2580. // blocking.
  2581. //
  2582. rfcb->ShareType = WorkContext->TreeConnect->Share->ShareType;
  2583. if ( rfcb->ShareType == ShareTypePipe ) {
  2584. rfcb->BlockingModePipe = TRUE;
  2585. rfcb->ByteModePipe = TRUE;
  2586. }
  2587. //
  2588. // Link the RFCB into the LFCB.
  2589. //
  2590. SrvInsertTailList( &lfcb->RfcbList, &pagedRfcb->LfcbListEntry );
  2591. rfcb->Lfcb = lfcb;
  2592. lfcb->BlockHeader.ReferenceCount++;
  2593. UPDATE_REFERENCE_HISTORY( lfcb, FALSE );
  2594. lfcb->HandleCount++;
  2595. rfcbLinkedToLfcb = TRUE;
  2596. //
  2597. // Making a new RFCB visible is a multi-step operation. It must be
  2598. // inserted in the global ordered file list and the containing
  2599. // connection's file table. If the LFCB is not new, it must be
  2600. // inserted in the MFCB's list of LFCBs, and the connection, the
  2601. // session, and the tree connect must all be referenced. We need to
  2602. // make these operations appear atomic, so that the RFCB cannot be
  2603. // accessed elsewhere before we're done setting it up. In order to
  2604. // do this, we hold all necessary locks the entire time we're doing
  2605. // the operations. The locks that are required are:
  2606. //
  2607. // 1) the MFCB lock (which protects the MFCB's LFCB list),
  2608. //
  2609. // 2) the global ordered list lock (which protects the ordered file
  2610. // list),
  2611. //
  2612. // 3) the connection lock (which prevents closing of the
  2613. // connection, the session, and the tree connect), and
  2614. //
  2615. // These locks are taken out in the order listed above, as dictated
  2616. // by lock levels (see lock.h). Note that the MFCB lock is already
  2617. // held on entry to this routine.
  2618. //
  2619. connection = WorkContext->Connection;
  2620. ASSERT( ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(Mfcb->NonpagedMfcb->Lock)) );
  2621. ASSERT( SrvRfcbList.Lock == &SrvOrderedListLock );
  2622. ACQUIRE_LOCK( SrvRfcbList.Lock );
  2623. ACQUIRE_LOCK( &connection->Lock );
  2624. //
  2625. // We first check all conditions to make sure that we can actually
  2626. // insert this RFCB.
  2627. //
  2628. // Make sure that the tree connect isn't closing.
  2629. //
  2630. if ( GET_BLOCK_STATE(WorkContext->TreeConnect) != BlockStateActive ) {
  2631. //
  2632. // The tree connect is closing. Reject the request.
  2633. //
  2634. IF_DEBUG(ERRORS) {
  2635. KdPrint(( "CompleteOpen: Tree connect is closing\n" ));
  2636. }
  2637. status = STATUS_INVALID_PARAMETER;
  2638. goto cant_insert;
  2639. }
  2640. //
  2641. // Make sure that the session isn't closing.
  2642. //
  2643. if ( GET_BLOCK_STATE(WorkContext->Session) != BlockStateActive ) {
  2644. //
  2645. // The session is closing. Reject the request.
  2646. //
  2647. IF_DEBUG(ERRORS) {
  2648. KdPrint(( "CompleteOpen: Session is closing\n" ));
  2649. }
  2650. status = STATUS_INVALID_PARAMETER;
  2651. goto cant_insert;
  2652. }
  2653. //
  2654. // Make sure that the connection isn't closing.
  2655. //
  2656. connection = WorkContext->Connection;
  2657. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  2658. //
  2659. // The connection is closing. Reject the request.
  2660. //
  2661. IF_DEBUG(ERRORS) {
  2662. KdPrint(( "CompleteOpen: Connection closing\n" ));
  2663. }
  2664. status = STATUS_INVALID_PARAMETER;
  2665. goto cant_insert;
  2666. }
  2667. //
  2668. // Find and claim a FID that can be used for this file.
  2669. //
  2670. entry = FindAndClaimFileTableEntry( connection, &fidIndex );
  2671. if ( entry == NULL ) {
  2672. //
  2673. // No free entries in the file table. Reject the request.
  2674. //
  2675. IF_DEBUG(ERRORS) {
  2676. KdPrint(( "CompleteOpen: No more FIDs available.\n" ));
  2677. }
  2678. SrvLogTableFullError( SRV_TABLE_FILE );
  2679. status = STATUS_OS2_TOO_MANY_OPEN_FILES;
  2680. goto cant_insert;
  2681. }
  2682. //
  2683. // All conditions have been satisfied. We can now do the things
  2684. // necessary to make the file visible.
  2685. //
  2686. // If this isn't a duplicate open, add this open file instance to
  2687. // the Master File Table.
  2688. //
  2689. if ( !ARGUMENT_PRESENT( ExistingLfcb ) ) {
  2690. //
  2691. // Add the new LFCB to the master file's list of open instances.
  2692. // We set LfcbAddedToMfcbList to tell the calling routine that
  2693. // an LFCB has been queued to the MFCB and that the reference
  2694. // count that was previously incremented should not be
  2695. // decremented.
  2696. //
  2697. *LfcbAddedToMfcbList = TRUE;
  2698. Mfcb->CompatibilityOpen = lfcb->CompatibilityOpen;
  2699. SrvInsertTailList( &Mfcb->LfcbList, &lfcb->MfcbListEntry );
  2700. lfcb->Mfcb = Mfcb;
  2701. //
  2702. // Point the LFCB to the connection, session, and tree connect,
  2703. // referencing them to account for the open file and therefore
  2704. // prevent deletion.
  2705. //
  2706. SrvReferenceConnection( connection );
  2707. lfcb->Connection = connection;
  2708. SrvReferenceSession( WorkContext->Session );
  2709. lfcb->Session = WorkContext->Session;
  2710. SrvReferenceTreeConnect( WorkContext->TreeConnect );
  2711. lfcb->TreeConnect = WorkContext->TreeConnect;
  2712. //
  2713. // Increment the count of open files in the session and tree
  2714. // connect. These counts prevent autodisconnecting a session
  2715. // that has open files and are used by server APIs.
  2716. //
  2717. WorkContext->Session->CurrentFileOpenCount++;
  2718. WorkContext->TreeConnect->CurrentFileOpenCount++;
  2719. }
  2720. //
  2721. // Capture the connection pointer in the nonpaged RFCB so that we
  2722. // can find the connection at DPC level.
  2723. //
  2724. rfcb->Connection = lfcb->Connection;
  2725. //
  2726. // Insert the RFCB on the global ordered list.
  2727. //
  2728. SrvInsertEntryOrderedList( &SrvRfcbList, rfcb );
  2729. //
  2730. // Set the owner and sequence number of the file table slot. Create
  2731. // a FID for the file.
  2732. //
  2733. entry->Owner = rfcb;
  2734. INCREMENT_FID_SEQUENCE( entry->SequenceNumber );
  2735. if ( fidIndex == 0 && entry->SequenceNumber == 0 ) {
  2736. INCREMENT_FID_SEQUENCE( entry->SequenceNumber );
  2737. }
  2738. rfcb->Fid = MAKE_FID( fidIndex, entry->SequenceNumber );
  2739. rfcb->ShiftedFid = rfcb->Fid << 16;
  2740. IF_SMB_DEBUG(OPEN_CLOSE2) {
  2741. KdPrint(( "CompleteOpen: Found FID. Index = 0x%lx, sequence = 0x%lx\n",
  2742. FID_INDEX( rfcb->Fid ), FID_SEQUENCE( rfcb->Fid ) ));
  2743. }
  2744. //
  2745. // Release the locks used to make this operation appear atomic.
  2746. //
  2747. // Note that our caller expects us to keep the MFCB lock held.
  2748. //
  2749. RELEASE_LOCK( &connection->Lock );
  2750. RELEASE_LOCK( SrvRfcbList.Lock );
  2751. //
  2752. // File successfully opened. Save in the WorkContext block for
  2753. // the followon SMB, if any. Cache the Rfcb.
  2754. //
  2755. WorkContext->Rfcb = rfcb;
  2756. *Rfcb = rfcb;
  2757. //
  2758. // Update the MFCB active count.
  2759. //
  2760. ++Mfcb->ActiveRfcbCount;
  2761. //
  2762. // If this is a pipe, set the client ID for the pipe. If it is a
  2763. // message type named pipe, set the read mode to message mode.
  2764. //
  2765. if ( rfcb->ShareType == ShareTypePipe ) {
  2766. //
  2767. // NT clients put the high part of the PID in a reserved
  2768. // location in the SMB header.
  2769. //
  2770. if ( IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  2771. pid = (SmbGetUshort( &WorkContext->RequestHeader->PidHigh )
  2772. << 16) | pid;
  2773. }
  2774. (VOID)SrvIssueSetClientProcessRequest(
  2775. lfcb->FileObject,
  2776. &lfcb->DeviceObject,
  2777. connection,
  2778. WorkContext->Session,
  2779. LongToPtr( pid )
  2780. );
  2781. //
  2782. // Set the read mode.
  2783. //
  2784. rfcb->ByteModePipe = !SetDefaultPipeMode( FileHandle );
  2785. }
  2786. return STATUS_SUCCESS;
  2787. cant_insert:
  2788. //
  2789. // Release the locks.
  2790. //
  2791. // Note that our caller expects us to keep the MFCB lock held.
  2792. //
  2793. RELEASE_LOCK( &connection->Lock );
  2794. RELEASE_LOCK( SrvRfcbList.Lock );
  2795. error_exit:
  2796. //
  2797. // Error cleanup. Put things back into their initial state.
  2798. //
  2799. // If the new RFCB was associated with an LFCB, unlink it now.
  2800. //
  2801. if ( rfcbLinkedToLfcb ) {
  2802. SrvRemoveEntryList(
  2803. &rfcb->Lfcb->RfcbList,
  2804. &pagedRfcb->LfcbListEntry
  2805. );
  2806. lfcb->BlockHeader.ReferenceCount--;
  2807. UPDATE_REFERENCE_HISTORY( lfcb, TRUE );
  2808. lfcb->HandleCount--;
  2809. }
  2810. //
  2811. // If the file object was referenced, dereference it.
  2812. //
  2813. if ( fileObject != NULL ) {
  2814. ObDereferenceObject( fileObject );
  2815. }
  2816. //
  2817. // If a new LFCB was allocated, free it.
  2818. //
  2819. if ( newLfcb != NULL ) {
  2820. SrvFreeLfcb( newLfcb, WorkContext->CurrentWorkQueue );
  2821. }
  2822. //
  2823. // If a new RFCB was allocated, free it.
  2824. //
  2825. if ( rfcb != NULL ) {
  2826. SrvFreeRfcb( rfcb, WorkContext->CurrentWorkQueue );
  2827. }
  2828. //
  2829. // If this not a folded compatibility mode open, close the file.
  2830. //
  2831. if ( !ARGUMENT_PRESENT( ExistingLfcb ) ) {
  2832. SRVDBG_RELEASE_HANDLE( FileHandle, "FIL", 17, 0 );
  2833. SrvNtClose( FileHandle, TRUE );
  2834. }
  2835. //
  2836. // Indicate failure.
  2837. //
  2838. *Rfcb = NULL;
  2839. return status;
  2840. } // CompleteOpen
  2841. BOOLEAN SRVFASTCALL
  2842. MapCompatibilityOpen(
  2843. IN PUNICODE_STRING FileName,
  2844. IN OUT PUSHORT SmbDesiredAccess
  2845. )
  2846. /*++
  2847. Routine Description:
  2848. Determines whether a compatibility mode open can be mapped into
  2849. normal sharing mode.
  2850. Arguments:
  2851. FileName - The name of the file being accessed
  2852. SmbDesiredAccess - On input, the desired access specified in the
  2853. received SMB. On output, the share mode portion of this field
  2854. is updated if the open is mapped to normal sharing.
  2855. Return Value:
  2856. BOOLEAN - TRUE if the open has been mapped to normal sharing.
  2857. --*/
  2858. {
  2859. PAGED_CODE( );
  2860. //
  2861. // If soft compatibility is not enabled then reject the mapping
  2862. //
  2863. if( !SrvEnableSoftCompatibility ) {
  2864. IF_SMB_DEBUG( OPEN_CLOSE2 ) {
  2865. KdPrint(( "MapCompatibilityOpen: "
  2866. "SrvEnableSoftCompatibility is FALSE\n" ));
  2867. }
  2868. return FALSE;
  2869. }
  2870. //
  2871. // If the client is opening one of the following reserved suffixes, be lenient
  2872. //
  2873. if( FileName->Length > 4 * sizeof( WCHAR ) ) {
  2874. LPWSTR periodp;
  2875. periodp = FileName->Buffer + (FileName->Length / sizeof( WCHAR ) ) - 4;
  2876. if( (*periodp++ == L'.') &&
  2877. (_wcsicmp( periodp, L"EXE" ) == 0 ||
  2878. _wcsicmp( periodp, L"DLL" ) == 0 ||
  2879. _wcsicmp( periodp, L"SYM" ) == 0 ||
  2880. _wcsicmp( periodp, L"COM" ) == 0 ) ) {
  2881. //
  2882. // This is a readonly open of one of the above file types.
  2883. // Map to DENY_NONE
  2884. //
  2885. IF_SMB_DEBUG( OPEN_CLOSE2 ) {
  2886. KdPrint(( "MapCompatibilityOpen: %wZ mapped to DENY_NONE\n", FileName ));
  2887. }
  2888. *SmbDesiredAccess |= SMB_DA_SHARE_DENY_NONE;
  2889. return TRUE;
  2890. }
  2891. }
  2892. //
  2893. // The filename does not end in one of the special suffixes -- map
  2894. // it to DENY_WRITE if the client is asking for just read permissions.
  2895. //
  2896. if( (*SmbDesiredAccess & SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ) {
  2897. IF_SMB_DEBUG( OPEN_CLOSE2 ) {
  2898. KdPrint(( "MapCompatibilityOpen: %wZ mapped to DENY_WRITE\n", FileName ));
  2899. }
  2900. *SmbDesiredAccess |= SMB_DA_SHARE_DENY_WRITE;
  2901. return TRUE;
  2902. }
  2903. IF_SMB_DEBUG( OPEN_CLOSE2 ) {
  2904. KdPrint(( "MapCompatibilityOpen: %wZ not mapped, DesiredAccess %X\n", FileName, *SmbDesiredAccess ));
  2905. }
  2906. return FALSE;
  2907. } // MapCompatibilityOpen
  2908. NTSTATUS SRVFASTCALL
  2909. MapDesiredAccess(
  2910. IN USHORT SmbDesiredAccess,
  2911. OUT PACCESS_MASK NtDesiredAccess
  2912. )
  2913. /*++
  2914. Routine Description:
  2915. Maps a desired access specification from SMB form to NT form.
  2916. Arguments:
  2917. SmbDesiredAccess - The desired access specified in the received SMB.
  2918. (This includes desired access, share access, and other mode
  2919. bits.)
  2920. NtDesiredAccess - Returns the NT equivalent of the desired access
  2921. part of SmbDesiredAccess.
  2922. Return Value:
  2923. NTSTATUS - Indicates whether SmbDesiredAccess is valid.
  2924. --*/
  2925. {
  2926. PAGED_CODE( );
  2927. switch ( SmbDesiredAccess & SMB_DA_ACCESS_MASK ) {
  2928. case SMB_DA_ACCESS_READ:
  2929. *NtDesiredAccess = GENERIC_READ;
  2930. break;
  2931. case SMB_DA_ACCESS_WRITE:
  2932. //
  2933. // Having read attributes is implicit in having the file open in
  2934. // the SMB protocol, so request FILE_READ_ATTRIBUTES in addition
  2935. // to GENERIC_WRITE.
  2936. //
  2937. *NtDesiredAccess = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
  2938. break;
  2939. case SMB_DA_ACCESS_READ_WRITE:
  2940. *NtDesiredAccess = GENERIC_READ | GENERIC_WRITE;
  2941. break;
  2942. case SMB_DA_ACCESS_EXECUTE:
  2943. // !!! is this right?
  2944. *NtDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
  2945. break;
  2946. default:
  2947. IF_DEBUG(SMB_ERRORS) {
  2948. KdPrint(( "MapDesiredAccess: Invalid desired access: 0x%lx\n",
  2949. SmbDesiredAccess ));
  2950. }
  2951. return STATUS_OS2_INVALID_ACCESS;
  2952. }
  2953. return STATUS_SUCCESS;
  2954. } // MapDesiredAccess
  2955. NTSTATUS SRVFASTCALL
  2956. MapOpenFunction(
  2957. IN USHORT SmbOpenFunction,
  2958. OUT PULONG NtCreateDisposition
  2959. )
  2960. /*++
  2961. Routine Description:
  2962. Maps an open function specification from SMB form to NT form.
  2963. Arguments:
  2964. WorkContext - Work context block for the operation.
  2965. SmbOpenFunction - The open function specified in the received SMB.
  2966. NtDesiredAccess - Returns the NT equivalent of SmbOpenFunction.
  2967. Return Value:
  2968. NTSTATUS - Indicates whether SmbOpenFunction is valid.
  2969. --*/
  2970. {
  2971. PAGED_CODE( );
  2972. // The OpenFunction bit mapping:
  2973. //
  2974. // rrrr rrrr rrrC rrOO
  2975. //
  2976. // where:
  2977. //
  2978. // C - Create (action to be taken if the file does not exist)
  2979. // 0 -- Fail
  2980. // 1 -- Create file
  2981. //
  2982. // O - Open (action to be taken if the file exists)
  2983. // 0 - Fail
  2984. // 1 - Open file
  2985. // 2 - Truncate file
  2986. //
  2987. switch ( SmbOpenFunction & (SMB_OFUN_OPEN_MASK | SMB_OFUN_CREATE_MASK) ) {
  2988. case SMB_OFUN_CREATE_FAIL | SMB_OFUN_OPEN_OPEN:
  2989. *NtCreateDisposition = FILE_OPEN;
  2990. break;
  2991. case SMB_OFUN_CREATE_CREATE | SMB_OFUN_OPEN_FAIL:
  2992. *NtCreateDisposition = FILE_CREATE;
  2993. break;
  2994. case SMB_OFUN_CREATE_CREATE | SMB_OFUN_OPEN_OPEN:
  2995. *NtCreateDisposition = FILE_OPEN_IF;
  2996. break;
  2997. case SMB_OFUN_CREATE_CREATE | SMB_OFUN_OPEN_TRUNCATE:
  2998. *NtCreateDisposition = FILE_OVERWRITE_IF;
  2999. break;
  3000. case SMB_OFUN_CREATE_FAIL | SMB_OFUN_OPEN_TRUNCATE:
  3001. *NtCreateDisposition = FILE_OVERWRITE;
  3002. break;
  3003. //case 0x00:
  3004. //case 0x03:
  3005. //case 0x13:
  3006. default:
  3007. IF_DEBUG(SMB_ERRORS) {
  3008. KdPrint(( "MapOpenFunction: Invalid open function: 0x%lx\n",
  3009. SmbOpenFunction ));
  3010. }
  3011. return STATUS_OS2_INVALID_ACCESS;
  3012. }
  3013. return STATUS_SUCCESS;
  3014. } // MapOpenFunction
  3015. NTSTATUS SRVFASTCALL
  3016. MapCacheHints(
  3017. IN USHORT SmbDesiredAccess,
  3018. IN OUT PULONG NtCreateFlags
  3019. )
  3020. /*++
  3021. Routine Description:
  3022. This function maps the SMB cache mode hints to the NT format. The
  3023. NtCreateFlags are updated.
  3024. Arguments:
  3025. WorkContext - Work context block for the operation.
  3026. SmbOpenFunction - The open function specified in the received SMB.
  3027. NtCreateFlags - The NT file creation flags
  3028. Return Value:
  3029. NTSTATUS - Indicates whether SmbOpenFunction is valid.
  3030. --*/
  3031. {
  3032. PAGED_CODE( );
  3033. // The DesiredAccess bit mapping:
  3034. //
  3035. // xxxC xLLL xxxx xxxx
  3036. //
  3037. // where:
  3038. //
  3039. // C - Cache mode
  3040. // 0 -- Normal file
  3041. // 1 -- Do not cache the file
  3042. //
  3043. // LLL - Locality of reference
  3044. // 000 - Unknown
  3045. // 001 - Mainly sequential access
  3046. // 010 - Mainly random access
  3047. // 011 - Random with some locality
  3048. // 1xx - Undefined
  3049. //
  3050. //
  3051. // If the client doesn't want us to use the cache, we can't give that, but we
  3052. // can at least get the data written immediately.
  3053. //
  3054. if ( SmbDesiredAccess & SMB_DO_NOT_CACHE ) {
  3055. *NtCreateFlags |= FILE_WRITE_THROUGH;
  3056. }
  3057. switch ( SmbDesiredAccess & SMB_LR_MASK ) {
  3058. case SMB_LR_UNKNOWN:
  3059. break;
  3060. case SMB_LR_SEQUENTIAL:
  3061. *NtCreateFlags |= FILE_SEQUENTIAL_ONLY;
  3062. break;
  3063. case SMB_LR_RANDOM:
  3064. case SMB_LR_RANDOM_WITH_LOCALITY:
  3065. *NtCreateFlags |= FILE_RANDOM_ACCESS;
  3066. break;
  3067. default:
  3068. IF_DEBUG(SMB_ERRORS) {
  3069. KdPrint(( "MapCacheHints: Invalid cache hint: 0x%lx\n",
  3070. SmbDesiredAccess ));
  3071. }
  3072. return STATUS_OS2_INVALID_ACCESS;
  3073. }
  3074. return STATUS_SUCCESS;
  3075. } // MapCacheHints
  3076. NTSTATUS SRVFASTCALL
  3077. MapShareAccess(
  3078. IN USHORT SmbDesiredAccess,
  3079. OUT PULONG NtShareAccess
  3080. )
  3081. /*++
  3082. Routine Description:
  3083. Maps a share access specification from SMB form to NT form.
  3084. Arguments:
  3085. SmbDesiredAccess - The desired access specified in the received SMB.
  3086. (This includes desired access, share access, and other mode
  3087. bits.)
  3088. NtShareAccess - Returns the NT equivalent of the share access part
  3089. of SmbDesiredAccess.
  3090. Return Value:
  3091. NTSTATUS - Indicates whether SmbDesiredAccess is valid.
  3092. --*/
  3093. {
  3094. PAGED_CODE( );
  3095. switch ( SmbDesiredAccess & SMB_DA_SHARE_MASK ) {
  3096. case SMB_DA_SHARE_EXCLUSIVE:
  3097. //
  3098. // Deny read and write.
  3099. //
  3100. *NtShareAccess = 0L;
  3101. break;
  3102. case SMB_DA_SHARE_DENY_WRITE:
  3103. //
  3104. // Deny write but allow read.
  3105. //
  3106. *NtShareAccess = FILE_SHARE_READ;
  3107. break;
  3108. case SMB_DA_SHARE_DENY_READ:
  3109. //
  3110. // Deny read but allow write.
  3111. //
  3112. *NtShareAccess = FILE_SHARE_WRITE;
  3113. break;
  3114. case SMB_DA_SHARE_DENY_NONE:
  3115. //
  3116. // Deny none -- allow other processes to read or write the file.
  3117. //
  3118. *NtShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
  3119. break;
  3120. default:
  3121. IF_DEBUG(SMB_ERRORS) {
  3122. KdPrint(( "MapShareAccess: Invalid share access: 0x%lx\n",
  3123. SmbDesiredAccess ));
  3124. }
  3125. return STATUS_OS2_INVALID_ACCESS;
  3126. }
  3127. return STATUS_SUCCESS;
  3128. } // MapShareAccess
  3129. NTSTATUS
  3130. SrvNtCreateFile(
  3131. IN OUT PWORK_CONTEXT WorkContext,
  3132. IN ULONG RootDirectoryFid,
  3133. IN ACCESS_MASK DesiredAccess,
  3134. IN LARGE_INTEGER AllocationSize,
  3135. IN ULONG FileAttributes,
  3136. IN ULONG ShareAccess,
  3137. IN ULONG CreateDisposition,
  3138. IN ULONG CreateOptions,
  3139. IN PVOID SecurityDescriptorBuffer OPTIONAL,
  3140. IN PUNICODE_STRING FileName,
  3141. IN PVOID EaBuffer OPTIONAL,
  3142. IN ULONG EaLength,
  3143. OUT PULONG EaErrorOffset OPTIONAL,
  3144. IN ULONG OptionFlags,
  3145. PSECURITY_QUALITY_OF_SERVICE QualityOfService,
  3146. IN OPLOCK_TYPE RequestedOplockType,
  3147. IN PRESTART_ROUTINE RestartRoutine
  3148. )
  3149. /*++
  3150. Routine Description:
  3151. Does most of the operations necessary to open or create a file.
  3152. First the UID and TID are verified and the corresponding session and
  3153. tree connect blocks located. The input file name name is
  3154. canonicalized, and a fully qualified name is formed. The file
  3155. is opened and the appropriate data structures are created.
  3156. Arguments:
  3157. WorkContext - Work context block for the operation.
  3158. RootDirectoryFid - The FID of an open root directory. The file is opened
  3159. relative to this directory.
  3160. DesiredAccess - The access type requested by the client.
  3161. AllocationSize - The initialize allocation size of the file. It is
  3162. only used if the file is created, overwritten, or superseded.
  3163. FileAttributes - Specified the file attributes.
  3164. ShareAccess - Specifies the type of share access requested by the
  3165. client.
  3166. CreateDisposition - Specifies the action to be taken if the file does
  3167. or does not exist.
  3168. CreateOptions - Specifies the options to use when creating the file.
  3169. SecurityDescriptorBuffer - The SD to set on the file.
  3170. FileName - The name of the file to open.
  3171. EaBuffer - The EAs to set on the file.
  3172. EaLength - Length, in bytes, of the EA buffer.
  3173. EaErrorOffset - Returns the offset, in bytes, in the EA buffer of
  3174. the EA error.
  3175. OptionFlags - The option flags for creating the file
  3176. QualityOfService - The security quality of service for the file
  3177. RestartRoutine - The restart routine for the caller.
  3178. Return Value:
  3179. NTSTATUS - Indicates what occurred.
  3180. --*/
  3181. {
  3182. NTSTATUS status;
  3183. NTSTATUS completionStatus;
  3184. PMFCB mfcb;
  3185. PNONPAGED_MFCB nonpagedMfcb;
  3186. PRFCB rfcb;
  3187. PSESSION session;
  3188. PTREE_CONNECT treeConnect;
  3189. UNICODE_STRING relativeName;
  3190. UNICODE_STRING fullName;
  3191. BOOLEAN nameAllocated;
  3192. BOOLEAN relativeNameAllocated = FALSE;
  3193. SHARE_TYPE shareType;
  3194. PRFCB rootDirRfcb = NULL;
  3195. PLFCB rootDirLfcb;
  3196. BOOLEAN success;
  3197. ULONG attributes;
  3198. ULONG openRetries;
  3199. OBJECT_ATTRIBUTES objectAttributes;
  3200. HANDLE fileHandle;
  3201. IO_STATUS_BLOCK ioStatusBlock;
  3202. ULONG ioCreateFlags;
  3203. PSHARE fileShare = NULL;
  3204. BOOLEAN caseInsensitive;
  3205. ULONG hashValue;
  3206. PSRV_LOCK mfcbLock;
  3207. //
  3208. // NOTE ON MFCB REFERENCE COUNT HANDLING
  3209. //
  3210. // After finding or creating an MFCB for a file, we increment the
  3211. // MFCB reference count an extra time to simplify our
  3212. // synchronization logic. We hold MfcbListLock lock while
  3213. // finding/creating the MFCB, but release it after acquiring the the
  3214. // per-MFCB lock. After opening the file, we call CompleteOpen,
  3215. // which may need to queue an LFCB to the MFCB and thus need to
  3216. // increment the count. But it can't, because the MFCB list lock may
  3217. // not be acquired while the per-MFCB lock is held because of
  3218. // deadlock potential. The boolean LfcbAddedToMfcbList returned
  3219. // from CompleteOpen indicates whether it actually queued an LFCB to
  3220. // the MFCB. If it didn't, we need to release the extra reference.
  3221. //
  3222. // Note that it isn't often that we actually have to dereference the
  3223. // MFCB. This only occurs when the open fails.
  3224. //
  3225. BOOLEAN lfcbAddedToMfcbList;
  3226. PAGED_CODE( );
  3227. //
  3228. // Assume we won't need a temporary open.
  3229. //
  3230. WorkContext->Parameters2.Open.TemporaryOpen = FALSE;
  3231. //
  3232. // If a session block has not already been assigned to the current
  3233. // work context, verify the UID. If verified, the address of the
  3234. // session block corresponding to this user is stored in the
  3235. // WorkContext block and the session block is referenced.
  3236. //
  3237. // Find the tree connect corresponding to the given TID if a tree
  3238. // connect pointer has not already been put in the WorkContext block
  3239. // by an AndX command or a previous call to SrvCreateFile.
  3240. //
  3241. status = SrvVerifyUidAndTid(
  3242. WorkContext,
  3243. &session,
  3244. &treeConnect,
  3245. ShareTypeWild
  3246. );
  3247. if ( !NT_SUCCESS(status) ) {
  3248. IF_DEBUG(SMB_ERRORS) {
  3249. KdPrint(( "SrvNtCreateFile: Invalid UID or TID\n" ));
  3250. }
  3251. return status;
  3252. }
  3253. //
  3254. // If the session has expired, return that info
  3255. //
  3256. if( session->IsSessionExpired )
  3257. {
  3258. return SESSION_EXPIRED_STATUS_CODE;
  3259. }
  3260. if ( RootDirectoryFid != 0 ) {
  3261. rootDirRfcb = SrvVerifyFid(
  3262. WorkContext,
  3263. (USHORT)RootDirectoryFid,
  3264. FALSE,
  3265. NULL, // don't serialize with raw write
  3266. &status
  3267. );
  3268. if ( rootDirRfcb == SRV_INVALID_RFCB_POINTER ) {
  3269. IF_DEBUG(ERRORS) {
  3270. KdPrint(( "SrvNtCreateFile: Invalid Root Dir FID: 0x%lx\n",
  3271. RootDirectoryFid ));
  3272. }
  3273. return status;
  3274. } else {
  3275. //
  3276. // Remove the redundant copy of the RFCB to prevent a redundant
  3277. // dereference of this RFCB.
  3278. //
  3279. WorkContext->Rfcb = NULL;
  3280. }
  3281. rootDirLfcb = rootDirRfcb->Lfcb;
  3282. }
  3283. //
  3284. // Here we begin share type specific processing.
  3285. //
  3286. shareType = treeConnect->Share->ShareType;
  3287. //
  3288. // If this operation may block, and we are running short of
  3289. // free work items, fail this SMB with an out of resources error.
  3290. // Note that a disk open will block if the file is currently oplocked.
  3291. //
  3292. if ( shareType == ShareTypeDisk && !WorkContext->BlockingOperation ) {
  3293. if ( SrvReceiveBufferShortage( ) ) {
  3294. if ( rootDirRfcb != NULL ) {
  3295. SrvDereferenceRfcb( rootDirRfcb );
  3296. }
  3297. SrvStatistics.BlockingSmbsRejected++;
  3298. return STATUS_INSUFF_SERVER_RESOURCES;
  3299. } else {
  3300. //
  3301. // SrvBlockingOpsInProgress has already been incremented.
  3302. // Flag this work item as a blocking operation.
  3303. //
  3304. WorkContext->BlockingOperation = TRUE;
  3305. }
  3306. }
  3307. //
  3308. // Assume we won't need a temporary open.
  3309. //
  3310. switch ( shareType ) {
  3311. case ShareTypeDisk:
  3312. case ShareTypePipe:
  3313. //
  3314. // Canonicalize the path name so that it conforms to NT
  3315. // standards.
  3316. //
  3317. // *** Note that this operation allocates space for the name.
  3318. //
  3319. status = SrvCanonicalizePathName(
  3320. WorkContext,
  3321. treeConnect->Share,
  3322. RootDirectoryFid != 0 ? &rootDirLfcb->Mfcb->FileName : NULL,
  3323. FileName->Buffer,
  3324. ((PCHAR)FileName->Buffer +
  3325. FileName->Length - sizeof(WCHAR)),
  3326. TRUE, // Strip trailing "."s
  3327. TRUE, // Name is always unicode
  3328. &relativeName
  3329. );
  3330. if ( !NT_SUCCESS( status ) ) {
  3331. //
  3332. // The path tried to do ..\ to get beyond the share it has
  3333. // accessed.
  3334. //
  3335. IF_DEBUG(ERRORS) {
  3336. KdPrint(( "SrvNtCreateFile: Invalid pathname: "
  3337. "%wZ\n", FileName ));
  3338. }
  3339. if ( rootDirRfcb != NULL ) {
  3340. SrvDereferenceRfcb( rootDirRfcb );
  3341. }
  3342. return status;
  3343. }
  3344. //
  3345. // Form the fully qualified name of the file.
  3346. //
  3347. // *** Note that this operation allocates space for the name.
  3348. // This space is deallocated after the DoXxxOpen routine
  3349. // returns.
  3350. //
  3351. if ( shareType == ShareTypeDisk ) {
  3352. if ( RootDirectoryFid != 0 ) {
  3353. SrvAllocateAndBuildPathName(
  3354. &rootDirLfcb->Mfcb->FileName,
  3355. &relativeName,
  3356. NULL,
  3357. &fullName
  3358. );
  3359. } else {
  3360. SrvAllocateAndBuildPathName(
  3361. &treeConnect->Share->DosPathName,
  3362. &relativeName,
  3363. NULL,
  3364. &fullName
  3365. );
  3366. }
  3367. } else {
  3368. UNICODE_STRING pipePrefix;
  3369. if( !WorkContext->Session->IsNullSession &&
  3370. WorkContext->Session->IsLSNotified == FALSE ) {
  3371. //
  3372. // We have a pipe open request, not a NULL session, and
  3373. // we haven't gotten clearance from the license server yet.
  3374. // If this pipe requires clearance, get a license.
  3375. //
  3376. ULONG i;
  3377. BOOLEAN matchFound = FALSE;
  3378. ACQUIRE_LOCK_SHARED( &SrvConfigurationLock );
  3379. for ( i = 0; SrvPipesNeedLicense[i] != NULL ; i++ ) {
  3380. if ( _wcsicmp(
  3381. SrvPipesNeedLicense[i],
  3382. relativeName.Buffer
  3383. ) == 0 ) {
  3384. matchFound = TRUE;
  3385. break;
  3386. }
  3387. }
  3388. RELEASE_LOCK( &SrvConfigurationLock );
  3389. if( matchFound == TRUE ) {
  3390. status = SrvXsLSOperation( WorkContext->Session,
  3391. XACTSRV_MESSAGE_LSREQUEST );
  3392. if( !NT_SUCCESS( status ) ) {
  3393. if( rootDirRfcb != NULL ) {
  3394. SrvDereferenceRfcb( rootDirRfcb );
  3395. }
  3396. return status;
  3397. }
  3398. }
  3399. }
  3400. RtlInitUnicodeString( &pipePrefix, StrSlashPipeSlash );
  3401. if( WorkContext->Endpoint->RemapPipeNames || treeConnect->RemapPipeNames ) {
  3402. //
  3403. // The RemapPipeNames flag is set, so remap the pipe name
  3404. // to "$$\<server>\<pipe name>".
  3405. //
  3406. // Note: this operation allocates space for pipeRelativeName.
  3407. //
  3408. status = RemapPipeName(
  3409. &WorkContext->Endpoint->TransportAddress,
  3410. treeConnect->RemapPipeNames ? &treeConnect->ServerName : NULL,
  3411. &relativeName,
  3412. &relativeNameAllocated
  3413. );
  3414. if( !NT_SUCCESS( status ) ) {
  3415. if( rootDirRfcb != NULL ) {
  3416. SrvDereferenceRfcb( rootDirRfcb );
  3417. }
  3418. return status;
  3419. }
  3420. }
  3421. SrvAllocateAndBuildPathName(
  3422. &pipePrefix,
  3423. &relativeName,
  3424. NULL,
  3425. &fullName
  3426. );
  3427. }
  3428. if ( fullName.Buffer == NULL ) {
  3429. //
  3430. // Unable to allocate heap for the full name.
  3431. //
  3432. IF_DEBUG(ERRORS) {
  3433. KdPrint(( "SrvNtCreateFile: Unable to allocate heap for "
  3434. "full path name\n" ));
  3435. }
  3436. if ( rootDirRfcb != NULL ) {
  3437. SrvDereferenceRfcb( rootDirRfcb );
  3438. }
  3439. if( relativeNameAllocated ) {
  3440. FREE_HEAP( relativeName.Buffer );
  3441. }
  3442. return STATUS_INSUFF_SERVER_RESOURCES;
  3443. }
  3444. //
  3445. // Indicate that we must free the file name buffers on exit.
  3446. //
  3447. nameAllocated = TRUE;
  3448. break;
  3449. //
  3450. // Default case, illegal device type. This should never happen.
  3451. //
  3452. default:
  3453. // !!! Is this an appropriate error return code? Probably no.
  3454. return STATUS_INVALID_PARAMETER;
  3455. }
  3456. //
  3457. // Determine whether or not the path name is case sensitive.
  3458. //
  3459. if ( (WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE) ||
  3460. WorkContext->Session->UsingUppercasePaths )
  3461. {
  3462. attributes = OBJ_CASE_INSENSITIVE;
  3463. caseInsensitive = TRUE;
  3464. } else {
  3465. attributes = 0L;
  3466. caseInsensitive = FALSE;
  3467. }
  3468. if ( RootDirectoryFid != 0 ) {
  3469. SrvInitializeObjectAttributes_U(
  3470. &objectAttributes,
  3471. &relativeName,
  3472. attributes,
  3473. rootDirLfcb->FileHandle,
  3474. NULL
  3475. );
  3476. } else if ( WorkContext->TreeConnect->Share->ShareType == ShareTypePipe ) {
  3477. SrvInitializeObjectAttributes_U(
  3478. &objectAttributes,
  3479. &relativeName,
  3480. attributes,
  3481. SrvNamedPipeHandle,
  3482. NULL
  3483. );
  3484. } else {
  3485. fileShare = treeConnect->Share;
  3486. SrvInitializeObjectAttributes_U(
  3487. &objectAttributes,
  3488. &relativeName,
  3489. attributes,
  3490. NULL,
  3491. NULL
  3492. );
  3493. }
  3494. if ( SecurityDescriptorBuffer != NULL) {
  3495. objectAttributes.SecurityDescriptor = SecurityDescriptorBuffer;
  3496. }
  3497. //
  3498. // Always add read attributes since we need to query file info after
  3499. // the open.
  3500. //
  3501. DesiredAccess |= FILE_READ_ATTRIBUTES;
  3502. //
  3503. // Interpret the io create flags
  3504. //
  3505. ioCreateFlags = IO_CHECK_CREATE_PARAMETERS | IO_FORCE_ACCESS_CHECK;
  3506. if ( OptionFlags & NT_CREATE_OPEN_TARGET_DIR ) {
  3507. ioCreateFlags |= IO_OPEN_TARGET_DIRECTORY;
  3508. }
  3509. //
  3510. // Override the default server quality of service, with the QOS request
  3511. // by the client.
  3512. //
  3513. objectAttributes.SecurityQualityOfService = QualityOfService;
  3514. if ( WorkContext->ProcessingCount == 2 ) {
  3515. HANDLE fileHandle;
  3516. OBJECT_ATTRIBUTES objectAttributes;
  3517. IO_STATUS_BLOCK ioStatusBlock;
  3518. //
  3519. // This is the second time through, so we must be in a blocking
  3520. // thread. Do a blocking open of the file to force an oplock
  3521. // break. Then close the handle and fall through to the normal
  3522. // open path.
  3523. //
  3524. // We must do the blocking open without holding the MFCB
  3525. // lock, because this lock can be acquired during oplock
  3526. // break, resulting in deadlock.
  3527. //
  3528. SrvInitializeObjectAttributes_U(
  3529. &objectAttributes,
  3530. &relativeName,
  3531. attributes,
  3532. 0,
  3533. NULL
  3534. );
  3535. status = SrvIoCreateFile(
  3536. WorkContext,
  3537. &fileHandle,
  3538. GENERIC_READ,
  3539. &objectAttributes,
  3540. &ioStatusBlock,
  3541. NULL,
  3542. 0,
  3543. FILE_SHARE_VALID_FLAGS,
  3544. FILE_OPEN,
  3545. 0,
  3546. NULL,
  3547. 0,
  3548. CreateFileTypeNone,
  3549. NULL, // ExtraCreateParameters
  3550. 0,
  3551. WorkContext->TreeConnect->Share
  3552. );
  3553. if ( NT_SUCCESS( status ) ) {
  3554. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 13, 0 );
  3555. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 18, 0 );
  3556. SrvNtClose( fileHandle, TRUE );
  3557. }
  3558. }
  3559. //
  3560. // Scan the Master File Table to see if the named file is already
  3561. // open.
  3562. //
  3563. mfcb = SrvFindMfcb( &fullName, caseInsensitive, &mfcbLock, &hashValue, WorkContext );
  3564. if ( mfcb == NULL ) {
  3565. //
  3566. // There is no MFCB for this file. Create one.
  3567. //
  3568. mfcb = SrvCreateMfcb( &fullName, WorkContext, hashValue );
  3569. if ( mfcb == NULL ) {
  3570. //
  3571. // Failure to add open file instance to MFT.
  3572. //
  3573. if( mfcbLock ) {
  3574. RELEASE_LOCK( mfcbLock );
  3575. }
  3576. IF_DEBUG(ERRORS) {
  3577. KdPrint(( "SrvNtCreateFile: Unable to allocate MFCB\n" ));
  3578. }
  3579. if ( nameAllocated ) {
  3580. FREE_HEAP( fullName.Buffer );
  3581. }
  3582. if( relativeNameAllocated ) {
  3583. FREE_HEAP( relativeName.Buffer );
  3584. }
  3585. if ( rootDirRfcb != NULL ) {
  3586. SrvDereferenceRfcb( rootDirRfcb );
  3587. }
  3588. return STATUS_INSUFF_SERVER_RESOURCES;
  3589. }
  3590. }
  3591. //
  3592. // Increment the MFCB reference count. See the note at the beginning of this routine.
  3593. //
  3594. mfcb->BlockHeader.ReferenceCount++;
  3595. UPDATE_REFERENCE_HISTORY( mfcb, FALSE );
  3596. //
  3597. // Grab the MFCB-based lock to serialize opens of the same file
  3598. // and release the MFCB list lock.
  3599. //
  3600. nonpagedMfcb = mfcb->NonpagedMfcb;
  3601. RELEASE_LOCK( mfcbLock );
  3602. ACQUIRE_LOCK( &nonpagedMfcb->Lock );
  3603. openRetries = SrvSharingViolationRetryCount;
  3604. start_retry:
  3605. //
  3606. // If the client asked for FILE_NO_INTERMEDIATE_BUFFERING, turn that
  3607. // flag off and turn FILE_WRITE_THROUGH on instead. We cannot give
  3608. // the client the true meaning of NO_INTERMEDIATE_BUFFERING, but we
  3609. // can at least get the data out to disk right away.
  3610. //
  3611. if ( (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) != 0 ) {
  3612. CreateOptions |= FILE_WRITE_THROUGH;
  3613. CreateOptions &= ~FILE_NO_INTERMEDIATE_BUFFERING;
  3614. }
  3615. //
  3616. // Check to see if there is a cached handle for the file.
  3617. //
  3618. if ( (CreateDisposition == FILE_OPEN) ||
  3619. (CreateDisposition == FILE_CREATE) ||
  3620. (CreateDisposition == FILE_OPEN_IF) ) {
  3621. IF_DEBUG(FILE_CACHE) {
  3622. KdPrint(( "SrvNtCreateFile: checking for cached rfcb for %wZ\n", &fullName ));
  3623. }
  3624. if ( SrvFindCachedRfcb(
  3625. WorkContext,
  3626. mfcb,
  3627. DesiredAccess,
  3628. ShareAccess,
  3629. CreateDisposition,
  3630. CreateOptions,
  3631. RequestedOplockType,
  3632. &status ) ) {
  3633. IF_DEBUG(FILE_CACHE) {
  3634. KdPrint(( "SrvNtCreateFile: FindCachedRfcb = TRUE, status = %x, rfcb = %p\n",
  3635. status, WorkContext->Rfcb ));
  3636. }
  3637. RELEASE_LOCK( &nonpagedMfcb->Lock );
  3638. //
  3639. // We incremented the MFCB reference count in anticipation of
  3640. // the possibility that an LFCB might be queued to the MFCB.
  3641. // This path precludes that possibility.
  3642. //
  3643. SrvDereferenceMfcb( mfcb );
  3644. //
  3645. // This second dereference is for the reference done by
  3646. // SrvFindMfcb/SrvCreateMfcb.
  3647. //
  3648. SrvDereferenceMfcb( mfcb );
  3649. if ( nameAllocated ) {
  3650. FREE_HEAP( fullName.Buffer );
  3651. }
  3652. if( relativeNameAllocated ) {
  3653. FREE_HEAP( relativeName.Buffer );
  3654. }
  3655. if ( rootDirRfcb != NULL ) {
  3656. SrvDereferenceRfcb( rootDirRfcb );
  3657. }
  3658. return status;
  3659. }
  3660. IF_DEBUG(FILE_CACHE) {
  3661. KdPrint(( "SrvNtCreateFile: FindCachedRfcb = FALSE; do it the slow way\n" ));
  3662. }
  3663. }
  3664. //
  3665. // Call SrvIoCreateFile to create or open the file. (We call
  3666. // SrvIoCreateFile, rather than NtOpenFile, in order to get user-mode
  3667. // access checking.)
  3668. //
  3669. IF_SMB_DEBUG(OPEN_CLOSE2) {
  3670. KdPrint(( "SrvCreateFile: Opening file %wZ\n", &fullName ));
  3671. }
  3672. CreateOptions |= FILE_COMPLETE_IF_OPLOCKED;
  3673. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  3674. //
  3675. // Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
  3676. // component, the Io subsystem does not check it for us.
  3677. //
  3678. if( ARGUMENT_PRESENT( EaBuffer ) ) {
  3679. status = IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION)EaBuffer, EaLength, EaErrorOffset );
  3680. } else {
  3681. status = STATUS_SUCCESS;
  3682. }
  3683. if( NT_SUCCESS( status ) ) {
  3684. status = SrvIoCreateFile(
  3685. WorkContext,
  3686. &fileHandle,
  3687. DesiredAccess,
  3688. &objectAttributes,
  3689. &ioStatusBlock,
  3690. &AllocationSize,
  3691. FileAttributes,
  3692. ShareAccess,
  3693. CreateDisposition,
  3694. CreateOptions,
  3695. EaBuffer,
  3696. EaLength,
  3697. CreateFileTypeNone,
  3698. NULL, // ExtraCreateParameters
  3699. ioCreateFlags,
  3700. fileShare
  3701. );
  3702. }
  3703. //
  3704. // If we got sharing violation and this is a disk file.
  3705. // If this is the first open attempt, setup for a blocking open attempt.
  3706. // If the file is batch oplocked, the non-blocking open would fail,
  3707. // and the oplock will not break.
  3708. //
  3709. // If this is the second open attempt, we can assume that we are in
  3710. // the blocking thread. Retry the open.
  3711. //
  3712. if ( status == STATUS_SHARING_VIOLATION &&
  3713. WorkContext->TreeConnect->Share->ShareType == ShareTypeDisk ) {
  3714. if ( WorkContext->ProcessingCount == 1 ) {
  3715. WorkContext->Parameters2.Open.TemporaryOpen = TRUE;
  3716. } else if ( (WorkContext->ProcessingCount == 2) &&
  3717. (openRetries-- > 0) ) {
  3718. //
  3719. // We are in the blocking thread.
  3720. //
  3721. //
  3722. // Release the mfcb lock so that a close might slip through.
  3723. //
  3724. RELEASE_LOCK( &nonpagedMfcb->Lock );
  3725. (VOID) KeDelayExecutionThread(
  3726. KernelMode,
  3727. FALSE,
  3728. &SrvSharingViolationDelay
  3729. );
  3730. ACQUIRE_LOCK( &nonpagedMfcb->Lock );
  3731. goto start_retry;
  3732. }
  3733. }
  3734. //
  3735. // Save the open information where the SMB processor can find it.
  3736. //
  3737. WorkContext->Irp->IoStatus.Information = ioStatusBlock.Information;
  3738. //
  3739. // If the user didn't have this permission, update the statistics
  3740. // database.
  3741. //
  3742. if ( status == STATUS_ACCESS_DENIED ) {
  3743. SrvStatistics.AccessPermissionErrors++;
  3744. }
  3745. if ( !NT_SUCCESS(status) ) {
  3746. //
  3747. // The open failed.
  3748. //
  3749. IF_DEBUG(ERRORS) {
  3750. KdPrint(( "SrvNtCreateFile: SrvIoCreateFile failed, file = %wZ, "
  3751. "status = %X, Info = 0x%p\n",
  3752. objectAttributes.ObjectName,
  3753. status, (PVOID)ioStatusBlock.Information ));
  3754. }
  3755. //
  3756. // Set the error offset if needed.
  3757. //
  3758. if ( ARGUMENT_PRESENT(EaErrorOffset) &&
  3759. status == STATUS_INVALID_EA_NAME ) {
  3760. *EaErrorOffset = (ULONG)ioStatusBlock.Information;
  3761. ioStatusBlock.Information = 0;
  3762. }
  3763. //
  3764. // Cleanup allocated memory and return with a failure status.
  3765. //
  3766. RELEASE_LOCK( &nonpagedMfcb->Lock );
  3767. //
  3768. // We incremented the MFCB reference count in anticipation of
  3769. // the possibility that an LFCB might be queued to the MFCB.
  3770. // This error path precludes that possibility.
  3771. //
  3772. SrvDereferenceMfcb( mfcb );
  3773. //
  3774. // This second dereference is for the reference done by
  3775. // SrvFindMfcb/SrvCreateMfcb.
  3776. //
  3777. SrvDereferenceMfcb( mfcb );
  3778. if ( nameAllocated ) {
  3779. FREE_HEAP( fullName.Buffer );
  3780. }
  3781. if( relativeNameAllocated ) {
  3782. FREE_HEAP( relativeName.Buffer );
  3783. }
  3784. if ( rootDirRfcb != NULL ) {
  3785. SrvDereferenceRfcb( rootDirRfcb );
  3786. }
  3787. return status;
  3788. }
  3789. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 14, 0 );
  3790. //
  3791. // The open was successful. Attempt to allocate structures to
  3792. // represent the open. If any errors occur, CompleteOpen does full
  3793. // cleanup, including closing the file.
  3794. //
  3795. IF_SMB_DEBUG(OPEN_CLOSE2) {
  3796. KdPrint(( "SrvNtCreateFile: Open of %wZ succeeded, file handle: 0x%p\n", &fullName, fileHandle ));
  3797. }
  3798. completionStatus = CompleteOpen(
  3799. &rfcb,
  3800. mfcb,
  3801. WorkContext,
  3802. NULL,
  3803. fileHandle,
  3804. NULL,
  3805. ShareAccess,
  3806. CreateOptions,
  3807. FALSE,
  3808. FALSE,
  3809. &lfcbAddedToMfcbList
  3810. );
  3811. //
  3812. // Remember the "interesting" status code. If CompleteOpen() succeeds
  3813. // return the open status. If it fails, it will clean up the open
  3814. // file, and we return a failure status.
  3815. //
  3816. if ( !NT_SUCCESS( completionStatus ) ) {
  3817. status = completionStatus;
  3818. }
  3819. //
  3820. // Release the Open serialization lock and dereference the MFCB.
  3821. //
  3822. RELEASE_LOCK( &nonpagedMfcb->Lock );
  3823. //
  3824. // If CompleteOpen didn't queue an LFCB to the MFCB, release the
  3825. // extra reference that we added.
  3826. //
  3827. if ( !lfcbAddedToMfcbList ) {
  3828. SrvDereferenceMfcb( mfcb );
  3829. }
  3830. SrvDereferenceMfcb( mfcb );
  3831. //
  3832. // Deallocate the full path name buffer.
  3833. //
  3834. if ( nameAllocated ) {
  3835. FREE_HEAP( fullName.Buffer );
  3836. }
  3837. //
  3838. // Deallocate the relative path name buffer.
  3839. //
  3840. if( relativeNameAllocated ) {
  3841. FREE_HEAP( relativeName.Buffer );
  3842. }
  3843. //
  3844. // Release our reference to the root directory RFCB
  3845. //
  3846. if ( rootDirRfcb != NULL ) {
  3847. SrvDereferenceRfcb( rootDirRfcb );
  3848. }
  3849. //
  3850. // If this is a temporary file, don't attempt to cache it.
  3851. //
  3852. if ( rfcb != NULL && (FileAttributes & FILE_ATTRIBUTE_TEMPORARY) != 0 ) {
  3853. rfcb->IsCacheable = FALSE;
  3854. }
  3855. //
  3856. // Update the statistics database if the open was successful.
  3857. //
  3858. if ( NT_SUCCESS(status) ) {
  3859. SrvStatistics.TotalFilesOpened++;
  3860. }
  3861. //
  3862. // Make a pointer to the RFCB accessible to the caller.
  3863. //
  3864. WorkContext->Parameters2.Open.Rfcb = rfcb;
  3865. //
  3866. // If there is an oplock break in progress, wait for the oplock
  3867. // break to complete.
  3868. //
  3869. if ( status == STATUS_OPLOCK_BREAK_IN_PROGRESS ) {
  3870. NTSTATUS startStatus;
  3871. //
  3872. // Save the Information from the open, so it doesn't
  3873. // get lost when we re-use the WorkContext->Irp for the
  3874. // oplock processing.
  3875. //
  3876. WorkContext->Parameters2.Open.IosbInformation = WorkContext->Irp->IoStatus.Information;
  3877. startStatus = SrvStartWaitForOplockBreak(
  3878. WorkContext,
  3879. RestartRoutine,
  3880. 0,
  3881. rfcb->Lfcb->FileObject
  3882. );
  3883. if (!NT_SUCCESS( startStatus ) ) {
  3884. //
  3885. // The file is oplocked, and we cannot wait for the oplock
  3886. // break to complete. Just close the file, and return the
  3887. // error.
  3888. //
  3889. SrvCloseRfcb( rfcb );
  3890. status = startStatus;
  3891. }
  3892. }
  3893. return status;
  3894. } // SrvNtCreateFile
  3895. BOOLEAN
  3896. SetDefaultPipeMode (
  3897. IN HANDLE FileHandle
  3898. )
  3899. /*++
  3900. Routine Description:
  3901. This function set the read mode of a newly opened named pipe. If
  3902. the pipe type is message mode, the read mode is set the message
  3903. mode.
  3904. Arguments:
  3905. FileHandle - The client side handle to the named pipe.
  3906. Return Value:
  3907. FALSE - Pipe mode is byte mode.
  3908. TRUE - Pipe mode has been set to message mode.
  3909. --*/
  3910. {
  3911. NTSTATUS status;
  3912. IO_STATUS_BLOCK ioStatusBlock;
  3913. FILE_PIPE_INFORMATION pipeInformation;
  3914. FILE_PIPE_LOCAL_INFORMATION pipeLocalInformation;
  3915. PAGED_CODE( );
  3916. status = NtQueryInformationFile(
  3917. FileHandle,
  3918. &ioStatusBlock,
  3919. (PVOID)&pipeLocalInformation,
  3920. sizeof(pipeLocalInformation),
  3921. FilePipeLocalInformation
  3922. );
  3923. if ( !NT_SUCCESS( status )) {
  3924. return FALSE;
  3925. }
  3926. if ( pipeLocalInformation.NamedPipeType != FILE_PIPE_MESSAGE_TYPE ) {
  3927. return FALSE;
  3928. }
  3929. pipeInformation.ReadMode = FILE_PIPE_MESSAGE_MODE;
  3930. pipeInformation.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
  3931. //
  3932. // ???: is it ok to ignore the return status for this call?
  3933. //
  3934. NtSetInformationFile(
  3935. FileHandle,
  3936. &ioStatusBlock,
  3937. (PVOID)&pipeInformation,
  3938. sizeof(pipeInformation),
  3939. FilePipeInformation
  3940. );
  3941. return TRUE;
  3942. } // SetDefaultPipeMode
  3943. BOOLEAN
  3944. SrvFailMdlReadDev (
  3945. IN PFILE_OBJECT FileObject,
  3946. IN PLARGE_INTEGER FileOffset,
  3947. IN ULONG Length,
  3948. IN ULONG LockKey,
  3949. OUT PMDL *MdlChain,
  3950. OUT PIO_STATUS_BLOCK IoStatus,
  3951. IN PDEVICE_OBJECT DeviceObject
  3952. )
  3953. {
  3954. return FALSE;
  3955. }
  3956. BOOLEAN
  3957. SrvFailPrepareMdlWriteDev (
  3958. IN PFILE_OBJECT FileObject,
  3959. IN PLARGE_INTEGER FileOffset,
  3960. IN ULONG Length,
  3961. IN ULONG LockKey,
  3962. OUT PMDL *MdlChain,
  3963. OUT PIO_STATUS_BLOCK IoStatus,
  3964. IN PDEVICE_OBJECT DeviceObject
  3965. )
  3966. {
  3967. return FALSE;
  3968. }