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

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